Redis
The Redis helper gives you one data API that works identically whether you are talking to a single node, a sharded cluster, or a Sentinel-managed high-availability pair.
In one example
Construct a single-node helper and round-trip a value through it.
import { RedisSingleHelper } from '@venizia/ignis-helpers';
const redis = new RedisSingleHelper({
name: 'cache',
host: 'localhost',
port: 6379,
password: 'secret',
});
await redis.set({ key: 'session:42', value: { userId: 42, active: true } });
const session = await redis.getObject<{ userId: number; active: boolean }>({
key: 'session:42',
});
console.log(session); // { userId: 42, active: true }autoConnect defaults to true, so the client starts connecting inside the constructor - no explicit connect() call needed for this example.
How it works
- Three topologies, one interface.
RedisSingleHelper,RedisClusterHelper, andRedisSentinelHelperall extendAbstractRedisHelperand implementIRedisHelper. Only the constructor options differ - the data API (get,hSet,publish, ...) is identical, so code written againstIRedisHelperworks with any topology unchanged.
| Topology | Class | Fits |
|---|---|---|
| Single node | RedisSingleHelper | One Redis instance |
| Cluster | RedisClusterHelper | Data sharded across nodes |
| Sentinel | RedisSentinelHelper | Automatic failover for one logical master |
- Pick a topology via the factory.
createRedisHelper({ mode })picks a topology from configuration - it is overloaded to return the concrete class whenmodeis a literal (RedisModes.SINGLE | CLUSTER | SENTINEL). - Connection lifecycle is automatic. With
autoConnect: true(default) the ioredis client starts connecting in the constructor; withautoConnect: falseyou callconnect()yourself. - Reconnects back off automatically. The backoff grows with each attempt, capped between 1 and 5 seconds, up to
maxRetryattempts (0= unlimited, the default;-1= no retry). - BullMQ compatibility differs by topology.
maxRetriesPerRequest: nullis always set for single and Sentinel helpers, which is what makes them BullMQ-compatible out of the box. Cluster does not get this automatically - see the Full reference. - Values are JSON-serialized automatically.
set,mSet,jSet, andjPushcallJSON.stringifybefore writing;getObject,getObjects, andjGetparse on read. Plainget/mGetreturn the raw stored string unless you pass atransformfunction - reach forgetObject/getObjectswhen you wrote the value withset. - Every method is camelCase.
hSet,lPush,sAdd- even where the underlying ioredis/Redis command is lowercase (hset,lpush,sadd). There is no lowercase alias.
Common tasks
Pick a topology
Switch topology by changing mode and its matching options; the rest of your code does not change.
import { createRedisHelper, RedisModes, type IRedisHelper } from '@venizia/ignis-helpers';
const redis: IRedisHelper = createRedisHelper({
mode: RedisModes.SINGLE, // or RedisModes.CLUSTER / RedisModes.SENTINEL
name: 'app-cache',
host: process.env.REDIS_HOST!,
port: Number(process.env.REDIS_PORT),
password: process.env.REDIS_PASSWORD!,
});See Full reference for the cluster (nodes) and Sentinel (sentinels, masterName) constructor shapes.
Cache a value with a TTL
options.expiresIn on set is in milliseconds, but ttl() reports remaining time in seconds - mixing the two up is the most common bug with this helper.
await redis.set({
key: 'session:42',
value: { userId: 42 },
options: { expiresIn: 60_000 }, // 60 seconds
});
const remaining = await redis.ttl({ key: 'session:42' }); // seconds; -1 = no expiry, -2 = missingPublish and subscribe
A subscribed ioredis connection cannot run regular commands, so use a second helper instance for subscribing and keep the first for data operations.
const subscriber = new RedisSingleHelper({ name: 'sub', host: 'localhost', port: 6379, password: 'secret' });
subscriber.subscribe({ topic: 'events' });
subscriber.getClient().on('message', (channel, message) => {
console.log(channel, JSON.parse(message.toString()));
});
await redis.publish({ topics: ['events'], payload: { type: 'user.created' } });Hashes, sets, and lists
Same key convention, one method family per data structure.
await redis.hSet({ key: 'user:42', value: { name: 'Ada', role: 'admin' } });
const role = await redis.hGet({ key: 'user:42', field: 'role' });
await redis.sAdd({ key: 'tags:42', members: ['vip', 'beta'] });
await redis.lPush({ key: 'queue:emails', values: ['welcome@example.com'] });Drop to a raw command
execute calls any ioredis command directly - useful for commands the typed API does not cover, like SCAN (prefer it over keys() in production, which blocks the server on large keyspaces).
const [cursor, matched] = await redis.execute<[string, string[]]>('SCAN', [
0,
'MATCH',
'user:*',
'COUNT',
100,
]);See also
- Full reference - every method group, topology option, and lifecycle event
- Queue Helper -
BullMQHelperuses a Redis helper as its connection backend - Socket.IO Component - resolves an
AbstractRedisHelperand callsduplicateClient()for its pub/sub adapter - Authorization Component - the cached Casbin enforcer uses the helper's
get/set/del - Migrating to the new Redis Helper API - renames and breaking changes from the pre-refactor API
Files:
packages/helpers/src/modules/redis/base/abstract.helper.ts-AbstractRedisHelper, the shared data APIpackages/helpers/src/modules/redis/single/single.helper.ts-RedisSingleHelperpackages/helpers/src/modules/redis/cluster/cluster.helper.ts-RedisClusterHelperpackages/helpers/src/modules/redis/sentinel/sentinel.helper.ts-RedisSentinelHelperpackages/helpers/src/modules/redis/factory.ts-createRedisHelperfactory