Member Junction
    Preparing search index...

    Redis-backed implementation of the MemberJunction ILocalStorageProvider interface.

    Provides persistent, shared caching for server-side environments using Redis. This is a drop-in replacement for InMemoryLocalStorageProvider — all consumers (like LocalCacheManager, ProviderBase metadata caching, etc.) work without any code changes.

    All keys follow the pattern: {prefix}:{category}:{key}

    • prefix — configurable, defaults to "mj" to isolate MJ data in shared Redis instances
    • category — maps to the MJ cache category (RunViewCache, Metadata, DatasetCache, etc.)
    • key — the original key from the caller

    Categories are tracked in a Redis Set at {prefix}:__categories__:{category} so that ClearCategory() and GetCategoryKeys() operations are efficient.

    Redis has native key expiration. The provider supports TTL at two levels:

    1. defaultTTLSeconds in config — applied to all SetItem calls
    2. ttlSeconds parameter on SetItem — overrides the default per-call

    Redis operations are wrapped in try/catch blocks. Connection errors are logged via LogError() but do not throw — the provider gracefully returns null for reads and silently skips writes. This prevents a Redis outage from crashing the application. The ioredis client handles automatic reconnection.

    import { RedisLocalStorageProvider } from '@memberjunction/redis-provider';

    const provider = new RedisLocalStorageProvider({
    url: 'redis://localhost:6379',
    defaultTTLSeconds: 300 // 5-minute default TTL
    });

    await provider.SetItem('user:123', JSON.stringify(userData), 'UserCache');
    const cached = await provider.GetItem('user:123', 'UserCache');

    Implements

    Index

    Constructors

    • Creates a new Redis local storage provider and establishes a connection.

      The constructor sets up the ioredis client with automatic reconnection, error handling, and optional logging. The client connects lazily on the first command, so construction itself does not block.

      Parameters

      • config: RedisProviderConfig = {}

        Redis connection and behavior configuration. At minimum, provide either url or options. If neither is provided, connects to localhost:6379.

      Returns RedisLocalStorageProvider

      // Connect to local Redis
      const provider = new RedisLocalStorageProvider({});

      // Connect to Azure Managed Redis with TLS
      const provider = new RedisLocalStorageProvider({
      url: 'rediss://default:ACCESS_KEY@myredis.redis.cache.windows.net:6380',
      defaultTTLSeconds: 600
      });

      // Connect to AWS ElastiCache
      const provider = new RedisLocalStorageProvider({
      options: {
      host: 'my-cluster.abc123.use1.cache.amazonaws.com',
      port: 6379,
      tls: {}
      }
      });

    Accessors

    • get Client(): Redis

      Returns the underlying ioredis client instance for advanced operations.

      Use with caution — direct client access bypasses key prefixing and category tracking. Prefer the ILocalStorageProvider methods for standard operations.

      Returns Redis

      // Use for Redis-specific commands like pub/sub, streams, etc.
      const client = provider.Client;
      await client.publish('cache-invalidation', 'entity:Users');
    • get IsConnected(): boolean

      Whether the Redis client currently has an active connection.

      Note: ioredis automatically reconnects on failure, so a false value here is usually transient. The provider continues to accept commands (they queue until reconnection succeeds or retry limit is hit).

      Returns boolean

    Methods

    • Clears all keys belonging to a specific category.

      Uses the category tracking Set to find all member keys, deletes them in a single pipeline call, then removes the tracking Set itself.

      Parameters

      • category: string

        The category to clear. If empty, clears the "default" category.

      Returns Promise<void>

      // Clear all cached RunView results
      await provider.ClearCategory('RunViewCache');
    • Gracefully disconnects from Redis.

      Sends a QUIT command and waits for pending replies. After calling this method, the provider should not be used for further operations.

      Call this during application shutdown to ensure clean disconnection.

      Returns Promise<void>

      // During application shutdown
      process.on('SIGTERM', async () => {
      await redisProvider.Disconnect();
      process.exit(0);
      });
    • Checks if a key exists in the specified category.

      This is more efficient than GetItem() when you only need to check existence without retrieving the value (avoids transferring the value over the network).

      Parameters

      • key: string

        The key to check

      • Optionalcategory: string

        Optional category for key isolation (defaults to "default")

      Returns Promise<boolean>

      true if the key exists and has not expired

      if (await provider.Exists('view:users', 'RunViewCache')) {
      // Use cached value
      }
    • Returns all keys belonging to a specific category.

      Reads from the category tracking Set, so the result reflects keys that were added via SetItem (some may have expired via TTL but will still appear in the set until cleaned up).

      Parameters

      • category: string

        The category to list keys from

      Returns Promise<string[]>

      Array of original key names (without the Redis prefix/category prefix)

      const keys = await provider.GetCategoryKeys('RunViewCache');
      console.log(`${keys.length} cached views`);
    • Retrieves a value from Redis by key and optional category.

      Redis stores values as strings — this method JSON-deserializes the stored value internally so callers see a typed object back. Returns null for missing keys, Redis unavailability, or corrupt JSON.

      Type Parameters

      • T = unknown

        Expected type of the stored value. Caller-controlled.

      Parameters

      • key: string

        The key to look up

      • Optionalcategory: string

        Optional category for key isolation (defaults to "default")

      Returns Promise<T | null>

      interface CachedEntity { ID: string; Name: string; }
      const value = await provider.GetItem<CachedEntity>('entity-metadata', 'Metadata');
      if (value) {
      console.log(value.Name); // already typed
      }
    • Batched read using Redis MGET — one command, one network round-trip, N values returned. For N keys this is ~N× faster than individual GETs which each pay full RTT.

      Inputs are deduplicated (same key requested twice → one Redis fetch, one map entry). Missing keys, corrupt JSON entries, and Redis errors all map to null for the affected key — callers see them as cache misses.

      Type Parameters

      • T = unknown

        Expected type of all stored values. Caller-controlled.

      Parameters

      • keys: string[]

        The keys to retrieve.

      • Optionalcategory: string

        Optional category for key isolation.

      Returns Promise<Map<string, T | null>>

    • Returns the remaining time-to-live (in seconds) for a key.

      Parameters

      • key: string

        The key to check

      • Optionalcategory: string

        Optional category for key isolation (defaults to "default")

      Returns Promise<number | null>

      TTL in seconds, -1 if no expiration is set, -2 if the key doesn't exist, or null if Redis is unavailable

      const ttl = await provider.GetTTL('view:users', 'RunViewCache');
      if (ttl !== null && ttl > 0) {
      console.log(`Key expires in ${ttl} seconds`);
      }
    • Registers a callback for cache change events from other servers. The callback fires whenever another server instance modifies a cached entry (via SetItem, Remove, or ClearCategory).

      Events from this server instance (identified by MJGlobal.ProcessUUID) are automatically filtered out.

      Parameters

      Returns () => void

      A function that, when called, removes this callback registration

      const unsubscribe = provider.OnCacheChanged((event) => {
      // Dispatch to LocalCacheManager for callback routing
      LocalCacheManager.Instance.DispatchCacheChange(event);
      });

      // Later, on shutdown:
      unsubscribe();
    • Pings the Redis server to verify connectivity.

      Useful for health checks and connection validation.

      Returns Promise<boolean>

      true if the server responds with PONG, false otherwise

      const healthy = await provider.Ping();
      if (!healthy) {
      console.error('Redis is unreachable');
      }
    • Removes a key from Redis and from its category tracking set.

      Parameters

      • key: string

        The key to remove

      • Optionalcategory: string

        Optional category for key isolation (defaults to "default")

      Returns Promise<void>

      await provider.Remove('view:users', 'RunViewCache');
      
    • Stores a value in Redis under the given key and optional category.

      Redis stores values as strings — this method JSON-serializes the value internally. Callers should pass plain data (objects/arrays/primitives). Class instances will lose their prototype on retrieval; functions, Maps, Sets, and Dates have JSON's usual limitations.

      If a ttlSeconds is provided, the key will automatically expire after that duration. Otherwise, the configured defaultTTLSeconds is used. If neither is set, the key persists indefinitely.

      The key is also added to a Redis Set that tracks all keys in the category, enabling efficient ClearCategory() and GetCategoryKeys() operations.

      Type Parameters

      • T

        Type of the value being stored. Caller-controlled.

      Parameters

      • key: string

        The key to store under

      • value: T

        The value to store (will be JSON-serialized internally)

      • Optionalcategory: string

        Optional category for key isolation (defaults to "default")

      • OptionalttlSeconds: number

        Optional time-to-live in seconds. Overrides defaultTTLSeconds from config.

      Returns Promise<void>

      // Store with default TTL
      await provider.SetItem('view:users', { results, maxUpdatedAt }, 'RunViewCache');

      // Store with explicit 10-minute TTL
      await provider.SetItem('view:users', { results }, 'RunViewCache', 600);
    • Starts listening for cache change events from other server instances. Creates a dedicated Redis connection for pub/sub (required by Redis protocol — a client in subscribe mode cannot execute other commands).

      Must be called explicitly after construction. No-op if enablePubSub is false in the config, or if already listening.

      Returns Promise<void>

      const provider = new RedisLocalStorageProvider({
      url: 'redis://localhost:6379',
      enablePubSub: true
      });
      await provider.StartListening();

      // Register for change events
      provider.OnCacheChanged((event) => {
      console.log(`Key "${event.CacheKey}" changed by server ${event.SourceServerId}`);
      });