🚨 Announcing Vendure v2 Beta

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.

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 IORedis from 'ioredis';

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

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

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

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

  async set(session: CachedSession) {
    await this.client.set(this.namespace(session.token), JSON.stringify(session));
  }

  async delete(sessionToken: string) {
    await this.client.del(this.namespace(sessionToken));
  }

  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>;
}

Extends

Members

set

method
type:
(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
type:
(sessionToken: string) => CachedSession | undefined | Promise<CachedSession | undefined>
Retrieve the session from the cache

delete

method
type:
(sessionToken: string) => void | Promise<void>
Delete a session from the cache

clear

method
type:
() => 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[];
}

Members

id

property
type:
ID

identifier

property
type:
string

verified

property
type:
boolean

channelPermissions

property
type:
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;
}

Members

cacheExpiry

property
type:
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
type:
ID

token

property
type:
string

expires

property
type:
Date

activeOrderId

property
type:
ID

authenticationStrategy

property
type:
string

user

property

activeChannelId

property
type:
ID