Skip to content

Redis

Utilities for Redis-backed caching, distributed locking, and inter-process communication.

Client Creation

typescript
import { createRedis, createRedisOptions } from '@zyno-io/ts-server-foundation';

// Create with default config (REDIS_HOST, REDIS_PORT)
const { client, prefix } = createRedis();

// Create with specific config prefix (uses CACHE_REDIS_* and falls back to REDIS_*)
const { client, prefix } = createRedis('CACHE');

Each call creates a separate connection and registers it with the current application. app.stop() closes those clients automatically, including clients acquired before a failed startup completes. disconnectAllRedis() remains available for callers that need to release every tracked Redis client before application shutdown.

Availability Alerts

The generic createAvailabilityMonitor() state machine logs one warning when a dependency becomes unavailable, reports one error if the outage lasts past the configured delay, and rearms after recovery. Call unavailable(error?) and available() from any dependency's lifecycle events.

monitorRedisAvailability() is the Redis-specific adapter. It maps ioredis error and reconnecting events to unavailable and ready to available:

typescript
import { monitorRedisAvailability } from '@zyno-io/ts-server-foundation';

const monitor = monitorRedisAvailability(client, logger, {
    alertAfterMs: config.REDIS_UNAVAILABLE_ALERT_AFTER_MS,
    name: 'SSE Redis'
});

The default delay is 60 seconds. This changes alert timing only; it does not slow or limit ioredis reconnection attempts.

Sentinel connections keep one subscription to Sentinel's +switch-master notifications so they reconnect as soon as a failover is announced without opening a detector connection to every discovered Sentinel. A READONLY response also forces master resolution and retries the rejected command, covering promotions where the old master socket remains open after becoming a replica.

Cache

Redis-backed cache with TTL support:

typescript
import { Cache } from '@zyno-io/ts-server-foundation';

// String values
await Cache.set('key', 'value', 3600); // TTL in seconds
const value = await Cache.get('key');

// Object values (auto JSON serialization)
await Cache.setObj('user:123', { name: 'Alice', role: 'admin' }, 3600);
const user = await Cache.getObj<{ name: string; role: string }>('user:123');
MethodDescription
Cache.get(key)Get a string value (returns null if missing)
Cache.set(key, val, ttl)Set a string value with TTL in seconds
Cache.getObj<T>(key)Get and deserialize a JSON value
Cache.setObj(key, val, ttl)Serialize and set a JSON value with TTL

Uses CACHE_REDIS_* environment variables (falls back to REDIS_*).

Distributed Mutex

Redis-backed distributed locking for coordinating work across multiple instances:

typescript
import { withMutex, withMutexes, MutexAcquisitionError } from '@zyno-io/ts-server-foundation';

// Single mutex
const result = await withMutex({
    key: ['user', userId],
    fn: async didWait => {
        // Critical section - only one instance executes at a time
        // didWait: true if we had to wait for the lock
        return await processPayment(userId);
    },
    retryCount: 30, // Max retry attempts (default: 30)
    retryDelay: 1000, // Delay between retries in ms (default: 1000)
    renewInterval: 1000 // Lock renewal interval in ms (default: 1000)
});

// Multiple mutexes (acquired in order)
const result = await withMutexes({
    keys: [
        ['resource', resourceA],
        ['resource', resourceB]
    ],
    fn: async didWait => {
        return await updateResources(resourceA, resourceB);
    }
});

Keys

Mutex keys can be primitives or arrays: ['resource', 123] becomes resource:123.

Error Handling

Throws MutexAcquisitionError if the lock cannot be acquired within the retry window.

Options

OptionTypeDefaultDescription
key / keysMutexKeyLock key(s) — string, number, or array
fn(didWait: boolean) => Promise<T>Function to execute under lock
retryCountnumber30Max retry attempts
retryDelaynumber1000Delay between retries (ms)
renewIntervalnumber1000Lock renewal interval (ms)

Modes

Configure via MUTEX_MODE:

  • local (default) — In-process locking with no Redis dependency. Useful for single-instance or testing scenarios.
  • redis — Uses Redis Lua scripts for atomic acquire/release/renew. Suitable for multi-instance deployments.

Uses MUTEX_REDIS_* environment variables (falls back to REDIS_*).

DevConsole Integration

Active mutexes and acquisition history are visible in the DevConsole Mutex view.

Broadcast Channels

Redis pub/sub for inter-process communication:

typescript
import { createBroadcastChannel } from '@zyno-io/ts-server-foundation';

// Create a typed broadcast channel
const channel = createBroadcastChannel<{ userId: string; action: string }>('user-events');

channel.subscribe(data => {
    console.log(`${data.userId}: ${data.action}`);
});

channel.publish({ userId: '123', action: 'login' });

Distributed Methods

Execute a function locally and broadcast to all instances:

typescript
import { createDistributedMethod } from '@zyno-io/ts-server-foundation';

class CacheManager {
    invalidate = createDistributedMethod<{ key: string }>(
        {
            name: 'invalidate',
            logger: () => this.logger
        },
        async data => {
            this.localCache.delete(data.key);
        }
    );
}

// Calling invalidate() runs locally AND broadcasts to all instances
await cacheManager.invalidate({ key: 'user:123' });

The logger option takes a getter function so it can reference this.logger even when used as a class field initializer. If omitted, a default logger scoped to Distributed:<name> is used.

Uses BROADCAST_REDIS_* environment variables (falls back to REDIS_*).

Configuration

All Redis utilities support independent connection configuration via environment variable prefixes:

UtilityEnv PrefixFallback
CacheCACHE_REDIS_*REDIS_*
MutexMUTEX_REDIS_*REDIS_*
BroadcastBROADCAST_REDIS_*REDIS_*
MeshMESH_REDIS_*REDIS_*
BullMQBULL_REDIS_*REDIS_*

Common variables for each prefix:

VariableDescriptionDefault
*_REDIS_HOSTRedis hostunset
*_REDIS_PORTRedis port6379
*_REDIS_PREFIXKey prefixpackage name
*_REDIS_SENTINEL_HOSTRedis Sentinel hostunset
*_REDIS_SENTINEL_PORTRedis Sentinel port26379
*_REDIS_SENTINEL_NAMERedis Sentinel master nameunset

For the default shared connection, omit the utility prefix and use REDIS_HOST, REDIS_PORT, REDIS_PREFIX, and REDIS_SENTINEL_*.

REDIS_UNAVAILABLE_ALERT_AFTER_MS controls the default outage grace period used with monitorRedisAvailability(). Its default is 60000.

Released under the MIT License.