RedisCache Driver: Distributed Caching Architecture & Configuration
RedisCache Driver: Distributed Caching Architecture
Section titled “RedisCache Driver: Distributed Caching Architecture”When scaling microservices horizontally or running multi-instance application
servers, process-local memory caches cannot share state across cluster nodes.
Xeno addresses this by providing RedisCache, an out-of-process, distributed
cache provider powered by the ioredis engine.
Understanding How RedisCache Works
Section titled “Understanding How RedisCache Works”The RedisCache driver acts as a distributed implementation of the framework’s
standard ICache interface. It translates generic caching primitives (get,
set, setIfAbsent, has, remove) into Redis commands, executing operations
over a centralized data store accessible by all server instances in your network
topology.
Under the hood, the driver is instantiated via RedisCacheFactory. It
configures an ioredis client with an automatic exponential reconnection
strategy to handle transient network blips and cluster failovers:
$$\text{delay} = \min(\text{times} \times 50, 2000) \text{ ms}$$
Key Operational Characteristics
Section titled “Key Operational Characteristics”-
Distributed State Synchronization — Cache state, query results, and idempotency locks are centralized, ensuring consistency across all application nodes.
-
Resilient Connection Handling — Native exponential retry backoff recalculates connection intervals automatically when network sockets drop.
-
Atomic Locks for Idempotency — Supports
setIfAbsentnatively (via RedisSET NX EXcommands) to prevent race conditions during concurrent command dispatching. -
Decoupled Architecture — Fully satisfies
ICache, allowing you to swap betweenInMemoryCacheandRedisCacheseamlessly without modifying application handlers.
graph TD A[App Instance 1] -->|Query / Lock| C[(Centralized Redis Cluster)] B[App Instance 2] -->|Query / Lock| C
subgraph Xeno Redis Cache Layer C -->|SET NX EX| D[Idempotency Locks] C -->|GET / SET| E[Cached Query Results] endConfiguring RedisCache via the AppBuilder Bootstrapper
Section titled “Configuring RedisCache via the AppBuilder Bootstrapper”Registering RedisCache is managed during host assembly using the fluent
AppBuilder configuration sequence. Under the hood, CacheUtils.addCache
evaluates the cache options. When a populated redis configuration block is
provided, RedisCacheFactory creates the underlying native Redis client and
binds RedisCache to TOKENS.CACHE.
Programmatic Bootstrap Registration Example
Section titled “Programmatic Bootstrap Registration Example”import { AppBuilder, TOKENS } from '@xeno-js/core'import type { AppRegistry } from './infrastructure/app-registry'
export const configureRedisCaching = async () => { const builder = new AppBuilder<AppRegistry>()
builder.addContext().addCache((opts, config) => { // 1. Enable Redis opts.redis = { host: config.getOrThrow('REDIS_HOST'), port: config.getNumber('REDIS_PORT', 6379), password: config.getOrThrow('REDIS_PASSWORD'), username: config.getOrThrow('REDIS_USERNAME'), tls: config.get('REDIS_TLS') === 'true', maxRetriesPerRequest: 3, } })
return await builder.build()}Understanding Redis Configuration Parameters
Section titled “Understanding Redis Configuration Parameters”The CacheClientConfig parameters dictate how RedisCacheFactory initializes
the native ioredis instance.
Key-Value Specification of Redis Configuration Options
Section titled “Key-Value Specification of Redis Configuration Options”-
host — The hostname or IP address of the target Redis server (defaults to
'localhost'if unsupplied). -
port — The TCP port used to connect to the Redis server (defaults to
6379). -
username — An optional username parameter required for Redis ACL-authenticated clusters.
-
password — An optional secret password string required for authenticated Redis instances.
-
tls — A boolean flag indicating whether to establish an encrypted TLS/SSL socket connection (defaults to
false). -
maxRetriesPerRequest — The maximum number of retry attempts permitted per queued request before raising a driver exception (defaults to
3).
Resolving and Utilizing RedisCache
Section titled “Resolving and Utilizing RedisCache”Application services, repositories, and handlers resolve RedisCache by
requesting TOKENS.CACHE from the service container. The container returns an
object implementing ICache, ensuring your business logic remains isolated from
Redis-specific logic.
Key-Value Specification of Exposed Methods
Section titled “Key-Value Specification of Exposed Methods”-
get
<T>(key) — Resolves a cached entry from Redis by key, returningPromise<Optional<T>>. Returnsundefinedif the key is missing or expired. -
set
<T>(key, value, ttlSeconds?) — Persists an entry in Redis with an optional expiration TTL in seconds. -
setIfAbsent
<T>(key, value, ttlSeconds?) — Atomically writes the entry only if the key does not already exist, returningtrueif saved orfalseif occupied. -
has(key) — Asynchronously returns
trueif the key exists in Redis. -
remove(key) — Evicts the target key from the Redis instance.
Programmatic Usage Example in an Application Service
Section titled “Programmatic Usage Example in an Application Service”import type { ICache } from '@xeno-js/core'
export class SessionService { constructor(private readonly _cache: ICache) {}
public async getSessionData( sessionId: string, ): Promise<Record<string, unknown> | null> { const key = `session:${sessionId}`
// 1. Attempt to fetch session payload from distributed Redis const session = await this._cache.get<Record<string, unknown>>(key) if (session) { return session }
return null }
public async acquireSessionLock( sessionId: string, lockTtl = 30, ): Promise<boolean> { const lockKey = `lock:session:${sessionId}`
// 2. Perform atomic conditional write (SET NX) for distributed concurrency control return await this._cache.setIfAbsent(lockKey, 'LOCKED', lockTtl) }
public async removeSession(sessionId: string): Promise<void> { const key = `session:${sessionId}` // 3. Evict entry from Redis cluster await this._cache.remove(key) }}Dependency Injection Registration Example
Section titled “Dependency Injection Registration Example”import { AppBuilder, TOKENS } from '@xeno-js/core';import { SessionService } from '../application/services/session.service';import type { AppRegistry } from './infrastructure/app-registry';
export const configureServices = async () => { const builder = new AppBuilder<AppRegistry>();
builder .addContext() .addCache((opts, config) => { // 1. Enable Redis Cache opts.redis = { host: config.getOrThrow('REDIS_HOST'), port: config.getNumber('REDIS_PORT', 6379), password: config.getOrThrow('REDIS_PASSWORD'), username: config.getOrThrow('REDIS_USERNAME'), tls: config.get('REDIS_TLS') === 'true', maxRetriesPerRequest: 3 }; }); .addServices((services) => { services.addScoped('SESSION_SERVICE', (container) => { // Resolve the global ICache instance (bound to RedisCache) const cache = container.resolve(TOKENS.CACHE); return new SessionService(cache); }); });
return await builder.build();};Installing Mandatory Peer Dependencies for Redis
Section titled “Installing Mandatory Peer Dependencies for Redis”To use the RedisCache driver, you must explicitly install the ioredis
package in your project. Because Xeno uses an optional peer dependency
model, external drivers are lazy-loaded to prevent bloating application
bundles that only require in-memory caching.
Execute the following package manager command within your project workspace:
# Install mandatory ioredis peer dependency for Redis supportnpm install ioredisNote: If you configure
opts.redisinsideCacheUtils.addCacheorAppBuilderwithout installingioredis, Node.js will throw a runtime module resolution exception during host initialization when attempting to importioredis.
Support Us
Section titled “Support Us”Xeno is an MIT-licensed open source project. It can grow thanks to the support of these awesome people. If you’d like to join them, please read more at support section