Skip to main content

SessionCacheStrategy

SessionCacheStrategy

This strategy defines how sessions get cached. Since most requests will need the Session object for permissions data, it can become a bottleneck to go to the database and do a multi-join SQL query each time. Therefore, we cache the session data only perform the SQL query once and upon invalidation of the cache.

The Vendure default is to use a the InMemorySessionCacheStrategy, which is fast and suitable for single-instance deployments. However, for multi-instance deployments (horizontally scaled, serverless etc.), you will need to define a custom strategy that stores the session cache in a shared data store, such as in the DB or in Redis.

info

This is configured via the authOptions.sessionCacheStrategy property of your VendureConfig.

Here's an example implementation using Redis. To use this, you need to add the ioredis package as a dependency.

Example

import { CachedSession, Logger, SessionCacheStrategy, VendurePlugin } from '@vendure/core';
import { Redis, RedisOptions } from 'ioredis';

export interface RedisSessionCachePluginOptions {
namespace?: string;
redisOptions?: RedisOptions;
}
const loggerCtx = 'RedisSessionCacheStrategy';
const DEFAULT_NAMESPACE = 'vendure-session-cache';
const DEFAULT_TTL = 86400;

export class RedisSessionCacheStrategy implements SessionCacheStrategy {
private client: Redis;
constructor(private options: RedisSessionCachePluginOptions) {}

init() {
this.client = new Redis(this.options.redisOptions as RedisOptions);
this.client.on('error', err => Logger.error(err.message, loggerCtx, err.stack));
}

async destroy() {
await this.client.quit();
}

async get(sessionToken: string): Promise<CachedSession | undefined> {
try {
const retrieved = await this.client.get(this.namespace(sessionToken));
if (retrieved) {
try {
return JSON.parse(retrieved);
} catch (e: any) {
Logger.error(`Could not parse cached session data: ${e.message}`, loggerCtx);
}
}
} catch (e: any) {
Logger.error(`Could not get cached session: ${e.message}`, loggerCtx);
}
}

async set(session: CachedSession) {
try {
await this.client.set(this.namespace(session.token), JSON.stringify(session), 'EX', DEFAULT_TTL);
} catch (e: any) {
Logger.error(`Could not set cached session: ${e.message}`, loggerCtx);
}
}

async delete(sessionToken: string) {
try {
await this.client.del(this.namespace(sessionToken));
} catch (e: any) {
Logger.error(`Could not delete cached session: ${e.message}`, loggerCtx);
}
}

clear() {
// not implemented
}

private namespace(key: string) {
return `${this.options.namespace ?? DEFAULT_NAMESPACE}:${key}`;
}
}

@VendurePlugin({
configuration: config => {
config.authOptions.sessionCacheStrategy = new RedisSessionCacheStrategy(
RedisSessionCachePlugin.options,
);
return config;
},
})
export class RedisSessionCachePlugin {
static options: RedisSessionCachePluginOptions;
static init(options: RedisSessionCachePluginOptions) {
this.options = options;
return this;
}
}
Signature
interface SessionCacheStrategy extends InjectableStrategy {
set(session: CachedSession): void | Promise<void>;
get(sessionToken: string): CachedSession | undefined | Promise<CachedSession | undefined>;
delete(sessionToken: string): void | Promise<void>;
clear(): void | Promise<void>;
}

set

method
(session: CachedSession) => void | Promise<void>

Store the session in the cache. When caching a session, the data should not be modified apart from performing any transforms needed to get it into a state to be stored, e.g. JSON.stringify().

get

method
(sessionToken: string) => CachedSession | undefined | Promise<CachedSession | undefined>

Retrieve the session from the cache

delete

method
(sessionToken: string) => void | Promise<void>

Delete a session from the cache

clear

method
() => void | Promise<void>

Clear the entire cache

CachedSessionUser

A simplified representation of the User associated with the current Session.

Signature
type CachedSessionUser = {
id: ID;
identifier: string;
verified: boolean;
channelPermissions: UserChannelPermissions[];
}

id

property

identifier

property
string

verified

property
boolean

channelPermissions

property
UserChannelPermissions[]

CachedSession

A simplified representation of a Session which is easy to store.

Signature
type CachedSession = {
cacheExpiry: number;
id: ID;
token: string;
expires: Date;
activeOrderId?: ID;
authenticationStrategy?: string;
user?: CachedSessionUser;
activeChannelId?: ID;
}

cacheExpiry

property
number

The timestamp after which this cache entry is considered stale and a fresh copy of the data will be set. Based on the sessionCacheTTL option.

id

property

token

property
string

expires

property
Date

activeOrderId

property

authenticationStrategy

property
string

user

activeChannelId

property