Skip to content

Redis

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

Client Creation

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

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

// Create with specific config prefix
const { client, prefix } = createRedis('CACHE_REDIS');

Each call creates a separate connection. All clients are tracked and can be disconnected with disconnectAllRedis().

Cache

Redis-backed cache with TTL support:

typescript
import { Cache } from '@zyno-io/dk-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/dk-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: [
        ['wallet', walletA],
        ['wallet', walletB]
    ],
    fn: async didWait => {
        return await transferFunds(walletA, walletB, amount);
    }
});

Keys

Mutex keys can be primitives or arrays: ['wallet', 123] becomes wallet: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:

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

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/dk-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/dk-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_*

Common variables for each prefix:

VariableDescriptionDefault
*_HOSTRedis host127.0.0.1
*_PORTRedis port6379
*_DBRedis database0
*_KEY_PREFIXKey prefix

Released under the MIT License.