@venizia/ignis-docs 0.0.5 → 0.0.6-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/wiki/best-practices/architecture-decisions.md +0 -8
- package/wiki/best-practices/code-style-standards/control-flow.md +1 -1
- package/wiki/best-practices/performance-optimization.md +3 -3
- package/wiki/best-practices/security-guidelines.md +2 -2
- package/wiki/best-practices/troubleshooting-tips.md +1 -1
- package/wiki/guides/core-concepts/components-guide.md +1 -1
- package/wiki/guides/core-concepts/components.md +2 -2
- package/wiki/guides/core-concepts/dependency-injection.md +1 -1
- package/wiki/guides/core-concepts/services.md +1 -1
- package/wiki/guides/tutorials/building-a-crud-api.md +1 -1
- package/wiki/guides/tutorials/ecommerce-api.md +2 -2
- package/wiki/guides/tutorials/realtime-chat.md +6 -6
- package/wiki/guides/tutorials/testing.md +1 -1
- package/wiki/references/base/bootstrapping.md +0 -2
- package/wiki/references/base/components.md +2 -2
- package/wiki/references/base/controllers.md +0 -1
- package/wiki/references/base/datasources.md +1 -1
- package/wiki/references/base/dependency-injection.md +1 -1
- package/wiki/references/base/filter-system/quick-reference.md +0 -14
- package/wiki/references/base/middlewares.md +0 -8
- package/wiki/references/base/providers.md +0 -9
- package/wiki/references/base/services.md +0 -1
- package/wiki/references/components/authentication/api.md +444 -0
- package/wiki/references/components/authentication/errors.md +177 -0
- package/wiki/references/components/authentication/index.md +571 -0
- package/wiki/references/components/authentication/usage.md +781 -0
- package/wiki/references/components/health-check.md +292 -103
- package/wiki/references/components/index.md +14 -12
- package/wiki/references/components/mail/api.md +505 -0
- package/wiki/references/components/mail/errors.md +176 -0
- package/wiki/references/components/mail/index.md +535 -0
- package/wiki/references/components/mail/usage.md +404 -0
- package/wiki/references/components/request-tracker.md +229 -25
- package/wiki/references/components/socket-io/api.md +1051 -0
- package/wiki/references/components/socket-io/errors.md +119 -0
- package/wiki/references/components/socket-io/index.md +410 -0
- package/wiki/references/components/socket-io/usage.md +322 -0
- package/wiki/references/components/static-asset/api.md +261 -0
- package/wiki/references/components/static-asset/errors.md +89 -0
- package/wiki/references/components/static-asset/index.md +617 -0
- package/wiki/references/components/static-asset/usage.md +364 -0
- package/wiki/references/components/swagger.md +390 -110
- package/wiki/references/components/template/api-page.md +125 -0
- package/wiki/references/components/template/errors-page.md +100 -0
- package/wiki/references/components/template/index.md +104 -0
- package/wiki/references/components/template/setup-page.md +134 -0
- package/wiki/references/components/template/single-page.md +132 -0
- package/wiki/references/components/template/usage-page.md +127 -0
- package/wiki/references/components/websocket/api.md +508 -0
- package/wiki/references/components/websocket/errors.md +123 -0
- package/wiki/references/components/websocket/index.md +453 -0
- package/wiki/references/components/websocket/usage.md +475 -0
- package/wiki/references/helpers/cron/index.md +224 -0
- package/wiki/references/helpers/crypto/index.md +537 -0
- package/wiki/references/helpers/env/index.md +214 -0
- package/wiki/references/helpers/error/index.md +232 -0
- package/wiki/references/helpers/index.md +16 -15
- package/wiki/references/helpers/inversion/index.md +608 -0
- package/wiki/references/helpers/logger/index.md +600 -0
- package/wiki/references/helpers/network/api.md +986 -0
- package/wiki/references/helpers/network/index.md +620 -0
- package/wiki/references/helpers/queue/index.md +589 -0
- package/wiki/references/helpers/redis/index.md +495 -0
- package/wiki/references/helpers/socket-io/api.md +497 -0
- package/wiki/references/helpers/socket-io/index.md +513 -0
- package/wiki/references/helpers/storage/api.md +705 -0
- package/wiki/references/helpers/storage/index.md +583 -0
- package/wiki/references/helpers/template/index.md +66 -0
- package/wiki/references/helpers/template/single-page.md +126 -0
- package/wiki/references/helpers/testing/index.md +510 -0
- package/wiki/references/helpers/types/index.md +512 -0
- package/wiki/references/helpers/uid/index.md +272 -0
- package/wiki/references/helpers/websocket/api.md +736 -0
- package/wiki/references/helpers/websocket/index.md +574 -0
- package/wiki/references/helpers/worker-thread/index.md +470 -0
- package/wiki/references/quick-reference.md +3 -18
- package/wiki/references/utilities/jsx.md +1 -8
- package/wiki/references/utilities/statuses.md +0 -7
- package/wiki/references/components/authentication.md +0 -476
- package/wiki/references/components/mail.md +0 -687
- package/wiki/references/components/socket-io.md +0 -562
- package/wiki/references/components/static-asset.md +0 -1277
- package/wiki/references/helpers/cron.md +0 -108
- package/wiki/references/helpers/crypto.md +0 -132
- package/wiki/references/helpers/env.md +0 -83
- package/wiki/references/helpers/error.md +0 -97
- package/wiki/references/helpers/inversion.md +0 -176
- package/wiki/references/helpers/logger.md +0 -296
- package/wiki/references/helpers/network.md +0 -396
- package/wiki/references/helpers/queue.md +0 -150
- package/wiki/references/helpers/redis.md +0 -142
- package/wiki/references/helpers/socket-io.md +0 -932
- package/wiki/references/helpers/storage.md +0 -665
- package/wiki/references/helpers/testing.md +0 -133
- package/wiki/references/helpers/types.md +0 -167
- package/wiki/references/helpers/uid.md +0 -167
- package/wiki/references/helpers/worker-thread.md +0 -178
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
# Redis
|
|
2
|
+
|
|
3
|
+
Powerful Redis abstraction supporting single instances and clusters via `ioredis`, with automatic JSON serialization, connection lifecycle callbacks, Pub/Sub with optional zlib compression, RedisJSON operations, and raw command execution.
|
|
4
|
+
|
|
5
|
+
## Quick Reference
|
|
6
|
+
|
|
7
|
+
| Class | Extends | Use Case |
|
|
8
|
+
|-------|---------|----------|
|
|
9
|
+
| **`DefaultRedisHelper`** | `BaseHelper` | Base class with unified API for all Redis operations |
|
|
10
|
+
| **`RedisHelper`** | `DefaultRedisHelper` | Single Redis instance with auto-connect and retry strategy |
|
|
11
|
+
| **`RedisClusterHelper`** | `DefaultRedisHelper` | Redis cluster with multi-node support |
|
|
12
|
+
|
|
13
|
+
#### Import Paths
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
// From the helpers package
|
|
17
|
+
import {
|
|
18
|
+
DefaultRedisHelper,
|
|
19
|
+
RedisHelper,
|
|
20
|
+
RedisClusterHelper,
|
|
21
|
+
} from '@venizia/ignis-helpers';
|
|
22
|
+
|
|
23
|
+
// Or from the core package (re-exports everything)
|
|
24
|
+
import {
|
|
25
|
+
DefaultRedisHelper,
|
|
26
|
+
RedisHelper,
|
|
27
|
+
RedisClusterHelper,
|
|
28
|
+
} from '@venizia/ignis';
|
|
29
|
+
|
|
30
|
+
// Types
|
|
31
|
+
import type {
|
|
32
|
+
IRedisHelperOptions,
|
|
33
|
+
IRedisClusterHelperOptions,
|
|
34
|
+
IRedisHelperCallbacks,
|
|
35
|
+
IRedisHelperProps,
|
|
36
|
+
IRedisClusterHelperProps,
|
|
37
|
+
} from '@venizia/ignis-helpers';
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Creating an Instance
|
|
41
|
+
|
|
42
|
+
### Single Instance
|
|
43
|
+
|
|
44
|
+
Use `RedisHelper` for connecting to a single Redis server.
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { RedisHelper } from '@venizia/ignis-helpers';
|
|
48
|
+
|
|
49
|
+
const redis = new RedisHelper({
|
|
50
|
+
name: 'my-redis',
|
|
51
|
+
host: 'localhost',
|
|
52
|
+
port: 6379,
|
|
53
|
+
password: 'secret',
|
|
54
|
+
database: 0,
|
|
55
|
+
autoConnect: true,
|
|
56
|
+
maxRetry: 5,
|
|
57
|
+
|
|
58
|
+
onInitialized: ({ name, helper }) => {
|
|
59
|
+
console.log(`Redis "${name}" initialized`);
|
|
60
|
+
},
|
|
61
|
+
onConnected: ({ name }) => {
|
|
62
|
+
console.log(`Redis "${name}" connected`);
|
|
63
|
+
},
|
|
64
|
+
onReady: ({ name }) => {
|
|
65
|
+
console.log(`Redis "${name}" ready`);
|
|
66
|
+
},
|
|
67
|
+
onError: ({ name, error }) => {
|
|
68
|
+
console.error(`Redis "${name}" error:`, error);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
#### `IRedisHelperOptions`
|
|
74
|
+
|
|
75
|
+
| Option | Type | Required | Default | Description |
|
|
76
|
+
|--------|------|----------|---------|-------------|
|
|
77
|
+
| `name` | `string` | Yes | -- | Unique identifier for this client instance |
|
|
78
|
+
| `host` | `string` | Yes | -- | Redis server hostname |
|
|
79
|
+
| `port` | `string \| number` | Yes | -- | Redis server port |
|
|
80
|
+
| `password` | `string` | Yes | -- | Redis password |
|
|
81
|
+
| `user` | `string` | No | -- | Redis username (ACL authentication) |
|
|
82
|
+
| `database` | `number` | No | `0` | Redis database index |
|
|
83
|
+
| `autoConnect` | `boolean` | No | `true` | Connect immediately on creation. When `false`, uses ioredis `lazyConnect` mode |
|
|
84
|
+
| `maxRetry` | `number` | No | `0` | Maximum reconnection attempts. `0` = unlimited retries. Values below `0` disable retry entirely |
|
|
85
|
+
| `onInitialized` | `(opts: { name: string; helper: DefaultRedisHelper }) => void` | No | -- | Called synchronously immediately after client construction |
|
|
86
|
+
| `onConnected` | `(opts: { name: string; helper: DefaultRedisHelper }) => void` | No | -- | Called when the TCP connection is established |
|
|
87
|
+
| `onReady` | `(opts: { name: string; helper: DefaultRedisHelper }) => void` | No | -- | Called when the client is ready to accept commands |
|
|
88
|
+
| `onError` | `(opts: { name: string; helper: DefaultRedisHelper; error: any }) => void` | No | -- | Called on connection or command errors |
|
|
89
|
+
|
|
90
|
+
**Retry strategy:** Exponential backoff clamped between 1s and 5s: `Math.max(Math.min(attempt * 2000, 5000), 1000)`. The ioredis option `maxRetriesPerRequest` is set to `null` internally, which is required for compatibility with BullMQ.
|
|
91
|
+
|
|
92
|
+
**ioredis configuration:** `RedisHelper` creates an ioredis `Redis` instance with `showFriendlyErrorStack: true` for better error diagnostics.
|
|
93
|
+
|
|
94
|
+
### Cluster
|
|
95
|
+
|
|
96
|
+
Use `RedisClusterHelper` for connecting to a Redis cluster.
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { RedisClusterHelper } from '@venizia/ignis-helpers';
|
|
100
|
+
|
|
101
|
+
const cluster = new RedisClusterHelper({
|
|
102
|
+
name: 'my-cluster',
|
|
103
|
+
nodes: [
|
|
104
|
+
{ host: 'redis-node-1', port: 7000 },
|
|
105
|
+
{ host: 'redis-node-2', port: 7001, password: 'node-specific-pass' },
|
|
106
|
+
{ host: 'redis-node-3', port: 7002 },
|
|
107
|
+
],
|
|
108
|
+
clusterOptions: {
|
|
109
|
+
redisOptions: { password: 'cluster-password' },
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
onReady: ({ name }) => {
|
|
113
|
+
console.log(`Cluster "${name}" ready`);
|
|
114
|
+
},
|
|
115
|
+
});
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### `IRedisClusterHelperOptions`
|
|
119
|
+
|
|
120
|
+
| Option | Type | Required | Default | Description |
|
|
121
|
+
|--------|------|----------|---------|-------------|
|
|
122
|
+
| `name` | `string` | Yes | -- | Unique identifier for this cluster client |
|
|
123
|
+
| `nodes` | `Array<{ host: string; port: string \| number; password?: string }>` | Yes | -- | List of cluster node addresses |
|
|
124
|
+
| `clusterOptions` | `ClusterOptions` | No | -- | ioredis `ClusterOptions` passed directly to the `Cluster` constructor |
|
|
125
|
+
| `onInitialized` | `(opts: { name: string; helper: DefaultRedisHelper }) => void` | No | -- | Called synchronously immediately after cluster client construction |
|
|
126
|
+
| `onConnected` | `(opts: { name: string; helper: DefaultRedisHelper }) => void` | No | -- | Called when connected |
|
|
127
|
+
| `onReady` | `(opts: { name: string; helper: DefaultRedisHelper }) => void` | No | -- | Called when ready |
|
|
128
|
+
| `onError` | `(opts: { name: string; helper: DefaultRedisHelper; error: any }) => void` | No | -- | Called on errors |
|
|
129
|
+
|
|
130
|
+
### Lifecycle Callbacks
|
|
131
|
+
|
|
132
|
+
All Redis helpers accept the same lifecycle callbacks via `IRedisHelperCallbacks`:
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
interface IRedisHelperCallbacks {
|
|
136
|
+
onInitialized?: (opts: { name: string; helper: DefaultRedisHelper }) => void;
|
|
137
|
+
onConnected?: (opts: { name: string; helper: DefaultRedisHelper }) => void;
|
|
138
|
+
onReady?: (opts: { name: string; helper: DefaultRedisHelper }) => void;
|
|
139
|
+
onError?: (opts: { name: string; helper: DefaultRedisHelper; error: any }) => void;
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
| Callback | Redis Event | When |
|
|
144
|
+
|----------|-------------|------|
|
|
145
|
+
| `onInitialized` | -- | Immediately after client construction (synchronous) |
|
|
146
|
+
| `onConnected` | `connect` | TCP connection established |
|
|
147
|
+
| `onReady` | `ready` | Client ready to accept commands |
|
|
148
|
+
| `onError` | `error` | Connection or command error |
|
|
149
|
+
|
|
150
|
+
Additionally, the client internally logs a warning on `reconnecting` events.
|
|
151
|
+
|
|
152
|
+
## Usage
|
|
153
|
+
|
|
154
|
+
All operations below are available on both `RedisHelper` and `RedisClusterHelper` via the shared `DefaultRedisHelper` base class.
|
|
155
|
+
|
|
156
|
+
### Connection Management
|
|
157
|
+
|
|
158
|
+
```typescript
|
|
159
|
+
// Manual connect (when autoConnect is false)
|
|
160
|
+
const connected = await redis.connect();
|
|
161
|
+
// => true if status becomes 'ready', false if already connected/connecting
|
|
162
|
+
|
|
163
|
+
// Disconnect gracefully (sends QUIT command)
|
|
164
|
+
const disconnected = await redis.disconnect();
|
|
165
|
+
// => true if quit succeeded
|
|
166
|
+
|
|
167
|
+
// Health check
|
|
168
|
+
const pong = await redis.ping();
|
|
169
|
+
// => 'PONG'
|
|
170
|
+
|
|
171
|
+
// Access underlying ioredis client
|
|
172
|
+
const ioredisClient = redis.getClient();
|
|
173
|
+
// RedisHelper returns Redis, RedisClusterHelper returns Cluster
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
> [!NOTE]
|
|
177
|
+
> `connect()` resolves to `false` without action if the client status is already `ready`, `reconnecting`, or `connecting`. Similarly, `disconnect()` resolves to `false` if the status is `end` or `close`.
|
|
178
|
+
|
|
179
|
+
### Key-Value Operations
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
// Set a value (auto-serialized to JSON)
|
|
183
|
+
await redis.set({ key: 'user:1', value: { name: 'Alice', age: 30 } });
|
|
184
|
+
|
|
185
|
+
// Set with logging enabled
|
|
186
|
+
await redis.set({ key: 'user:1', value: { name: 'Alice' }, options: { log: true } });
|
|
187
|
+
|
|
188
|
+
// Get raw string value
|
|
189
|
+
const raw = await redis.get({ key: 'user:1' });
|
|
190
|
+
// => '{"name":"Alice","age":30}'
|
|
191
|
+
|
|
192
|
+
// Get with custom transform
|
|
193
|
+
const parsed = await redis.get({
|
|
194
|
+
key: 'user:1',
|
|
195
|
+
transform: (input) => JSON.parse(input),
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
// Convenience: get as string (alias for get)
|
|
199
|
+
const str = await redis.getString({ key: 'user:1' });
|
|
200
|
+
|
|
201
|
+
// Convenience: get as parsed JSON object
|
|
202
|
+
const user = await redis.getObject({ key: 'user:1' });
|
|
203
|
+
// => { name: 'Alice', age: 30 }
|
|
204
|
+
|
|
205
|
+
// Delete keys
|
|
206
|
+
await redis.del({ keys: ['user:1', 'user:2'] });
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Multi-Key Operations
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
// Set multiple keys at once
|
|
213
|
+
await redis.mset({
|
|
214
|
+
payload: [
|
|
215
|
+
{ key: 'user:1', value: { name: 'Alice' } },
|
|
216
|
+
{ key: 'user:2', value: { name: 'Bob' } },
|
|
217
|
+
],
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Get multiple raw values
|
|
221
|
+
const values = await redis.mget({ keys: ['user:1', 'user:2'] });
|
|
222
|
+
// => ['{"name":"Alice"}', '{"name":"Bob"}']
|
|
223
|
+
|
|
224
|
+
// Get multiple with transform
|
|
225
|
+
const users = await redis.mget({
|
|
226
|
+
keys: ['user:1', 'user:2'],
|
|
227
|
+
transform: (el) => JSON.parse(el),
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
// Convenience: get multiple strings
|
|
231
|
+
const strings = await redis.getStrings({ keys: ['key1', 'key2'] });
|
|
232
|
+
|
|
233
|
+
// Convenience: get multiple parsed objects
|
|
234
|
+
const objects = await redis.getObjects({ keys: ['user:1', 'user:2'] });
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
> [!TIP]
|
|
238
|
+
> `mSet()`, `mGet()`, `hSet()`, and `hGetAll()` are camelCase aliases for `mset()`, `mget()`, `hset()`, and `hgetall()` respectively. Both forms are valid.
|
|
239
|
+
|
|
240
|
+
### Hash Operations
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
// Set hash fields
|
|
244
|
+
await redis.hset({
|
|
245
|
+
key: 'session:abc',
|
|
246
|
+
value: { userId: 'u1', token: 'tok123', createdAt: '2025-01-01' },
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Set hash fields with logging
|
|
250
|
+
await redis.hset({
|
|
251
|
+
key: 'session:abc',
|
|
252
|
+
value: { userId: 'u1' },
|
|
253
|
+
options: { log: true },
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
// Get all hash fields
|
|
257
|
+
const session = await redis.hgetall({ key: 'session:abc' });
|
|
258
|
+
// => { userId: 'u1', token: 'tok123', createdAt: '2025-01-01' }
|
|
259
|
+
|
|
260
|
+
// Get all hash fields with transform
|
|
261
|
+
const transformed = await redis.hgetall({
|
|
262
|
+
key: 'session:abc',
|
|
263
|
+
transform: (input) => ({ ...input, extra: true }),
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Key Scanning
|
|
268
|
+
|
|
269
|
+
```typescript
|
|
270
|
+
// Find keys matching a pattern
|
|
271
|
+
const matchingKeys = await redis.keys({ key: 'user:*' });
|
|
272
|
+
// => ['user:1', 'user:2', ...]
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
> [!WARNING]
|
|
276
|
+
> `keys()` uses the Redis `KEYS` command, which scans the entire keyspace. Avoid using it in production on large databases -- prefer `SCAN` via `execute()` instead.
|
|
277
|
+
|
|
278
|
+
### RedisJSON Operations
|
|
279
|
+
|
|
280
|
+
If your Redis server has the [RedisJSON](https://redis.io/docs/stack/json/) module installed, you can use the `j*` methods for native JSON document operations.
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
// Set a JSON document
|
|
284
|
+
await redis.jSet({ key: 'doc:1', path: '$', value: { name: 'Alice', scores: [10, 20] } });
|
|
285
|
+
|
|
286
|
+
// Get entire document (path defaults to '$')
|
|
287
|
+
const doc = await redis.jGet({ key: 'doc:1' });
|
|
288
|
+
|
|
289
|
+
// Get a nested path
|
|
290
|
+
const scores = await redis.jGet({ key: 'doc:1', path: '$.scores' });
|
|
291
|
+
|
|
292
|
+
// Delete a JSON path
|
|
293
|
+
await redis.jDelete({ key: 'doc:1', path: '$.scores' });
|
|
294
|
+
|
|
295
|
+
// Delete entire document (path defaults to '$')
|
|
296
|
+
await redis.jDelete({ key: 'doc:1' });
|
|
297
|
+
|
|
298
|
+
// Increment a number at a path
|
|
299
|
+
await redis.jNumberIncreaseBy({ key: 'doc:1', path: '$.counter', value: 5 });
|
|
300
|
+
|
|
301
|
+
// Append to a string at a path
|
|
302
|
+
await redis.jStringAppend({ key: 'doc:1', path: '$.name', value: ' Smith' });
|
|
303
|
+
|
|
304
|
+
// Push to an array at a path
|
|
305
|
+
await redis.jPush({ key: 'doc:1', path: '$.tags', value: 'new-tag' });
|
|
306
|
+
|
|
307
|
+
// Pop from an array at a path
|
|
308
|
+
const popped = await redis.jPop({ key: 'doc:1', path: '$.tags' });
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
#### RedisJSON Method Signatures
|
|
312
|
+
|
|
313
|
+
| Method | Parameters | Returns | Redis Command |
|
|
314
|
+
|--------|-----------|---------|---------------|
|
|
315
|
+
| `jSet<T>()` | `{ key: string; path: string; value: T }` | `Promise<string \| null>` | `JSON.SET` |
|
|
316
|
+
| `jGet<T>()` | `{ key: string; path?: string }` | `Promise<T \| null>` | `JSON.GET` |
|
|
317
|
+
| `jDelete()` | `{ key: string; path?: string }` | `Promise<number>` | `JSON.DEL` |
|
|
318
|
+
| `jNumberIncreaseBy()` | `{ key: string; path: string; value: number }` | `Promise<string \| null>` | `JSON.NUMINCRBY` |
|
|
319
|
+
| `jStringAppend()` | `{ key: string; path: string; value: string }` | `Promise<number[] \| null>` | `JSON.STRAPPEND` |
|
|
320
|
+
| `jPush<T>()` | `{ key: string; path: string; value: T }` | `Promise<number[] \| null>` | `JSON.ARRAPPEND` |
|
|
321
|
+
| `jPop<T>()` | `{ key: string; path: string }` | `Promise<T \| null>` | `JSON.ARRPOP` |
|
|
322
|
+
|
|
323
|
+
`jGet` and `jDelete` default `path` to `'$'` (root) when omitted. All other `j*` methods require `path` explicitly.
|
|
324
|
+
|
|
325
|
+
### Pub/Sub
|
|
326
|
+
|
|
327
|
+
The helper supports Redis Pub/Sub for real-time messaging with optional zlib compression.
|
|
328
|
+
|
|
329
|
+
```typescript
|
|
330
|
+
// Subscribe to a topic
|
|
331
|
+
redis.subscribe({ topic: 'events' });
|
|
332
|
+
|
|
333
|
+
// Listen for messages on the underlying ioredis client
|
|
334
|
+
redis.getClient().on('message', (channel, message) => {
|
|
335
|
+
if (channel === 'events') {
|
|
336
|
+
console.log('Received:', JSON.parse(message));
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
// Publish to one or more topics
|
|
341
|
+
await redis.publish({
|
|
342
|
+
topics: ['events', 'audit-log'],
|
|
343
|
+
payload: { action: 'user.created', userId: 'u1' },
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// Publish with zlib compression
|
|
347
|
+
await redis.publish({
|
|
348
|
+
topics: ['compressed-channel'],
|
|
349
|
+
payload: { large: 'dataset' },
|
|
350
|
+
useCompress: true,
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
// Unsubscribe from a topic
|
|
354
|
+
redis.unsubscribe({ topic: 'events' });
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
> [!IMPORTANT]
|
|
358
|
+
> When using Pub/Sub, the subscribing client enters subscriber mode and can only execute `SUBSCRIBE`, `PSUBSCRIBE`, `UNSUBSCRIBE`, `PUNSUBSCRIBE`, `PING`, and `QUIT` commands. Use a separate `RedisHelper` instance for Pub/Sub if you also need to perform regular data operations.
|
|
359
|
+
|
|
360
|
+
### Raw Command Execution
|
|
361
|
+
|
|
362
|
+
For commands not wrapped by the helper, use `execute()` to call any Redis command directly.
|
|
363
|
+
|
|
364
|
+
```typescript
|
|
365
|
+
// Execute any Redis command
|
|
366
|
+
const result = await redis.execute<string>('SET', ['mykey', 'myvalue', 'EX', 60]);
|
|
367
|
+
|
|
368
|
+
// Command without parameters
|
|
369
|
+
const info = await redis.execute<string>('INFO');
|
|
370
|
+
|
|
371
|
+
// SCAN instead of KEYS for production use
|
|
372
|
+
const [cursor, keys] = await redis.execute<[string, string[]]>(
|
|
373
|
+
'SCAN', [0, 'MATCH', 'user:*', 'COUNT', 100],
|
|
374
|
+
);
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## API Summary
|
|
378
|
+
|
|
379
|
+
| Method | Returns | Description |
|
|
380
|
+
|--------|---------|-------------|
|
|
381
|
+
| **Connection** | | |
|
|
382
|
+
| `connect()` | `Promise<boolean>` | Manual connect (no-op if already connected/connecting/ready) |
|
|
383
|
+
| `disconnect()` | `Promise<boolean>` | Graceful disconnect via `QUIT` (no-op if already ended/closed) |
|
|
384
|
+
| `ping()` | `Promise<string>` | Health check, returns `'PONG'` |
|
|
385
|
+
| `getClient()` | `Redis \| Cluster` | Access the underlying ioredis client |
|
|
386
|
+
| **Key-Value** | | |
|
|
387
|
+
| `set<T>(opts)` | `Promise<void>` | Set a key with JSON-serialized value. Options: `{ key, value, options?: { log } }` |
|
|
388
|
+
| `get<T>(opts)` | `Promise<T \| null>` | Get raw value with optional transform. Options: `{ key, transform? }` |
|
|
389
|
+
| `getString(opts)` | `Promise<string \| null>` | Get raw string value. Options: `{ key }` |
|
|
390
|
+
| `getObject(opts)` | `Promise<object \| null>` | Get value parsed as JSON. Options: `{ key }` |
|
|
391
|
+
| `del(opts)` | `Promise<number>` | Delete one or more keys. Options: `{ keys: string[] }` |
|
|
392
|
+
| **Multi-Key** | | |
|
|
393
|
+
| `mset<T>(opts)` / `mSet<T>(opts)` | `Promise<void>` | Set multiple key-value pairs. Options: `{ payload: Array<{ key, value }>, options?: { log } }` |
|
|
394
|
+
| `mget<T>(opts)` / `mGet<T>(opts)` | `Promise<(T \| null)[]>` | Get multiple values with optional transform. Options: `{ keys, transform? }` |
|
|
395
|
+
| `getStrings(opts)` | `Promise<(string \| null)[]>` | Get multiple raw string values. Options: `{ keys }` |
|
|
396
|
+
| `getObjects(opts)` | `Promise<(object \| null)[]>` | Get multiple values parsed as JSON. Options: `{ keys }` |
|
|
397
|
+
| **Hashes** | | |
|
|
398
|
+
| `hset<T>(opts)` / `hSet<T>(opts)` | `Promise<number>` | Set hash fields. Options: `{ key, value: Record<string, unknown>, options?: { log } }` |
|
|
399
|
+
| `hgetall(opts)` / `hGetAll(opts)` | `Promise<Record<string, string> \| null>` | Get all hash fields with optional transform. Options: `{ key, transform? }` |
|
|
400
|
+
| **Key Scanning** | | |
|
|
401
|
+
| `keys(opts)` | `Promise<string[]>` | Find keys matching a glob pattern. Options: `{ key }` |
|
|
402
|
+
| **RedisJSON** | | |
|
|
403
|
+
| `jSet<T>(opts)` | `Promise<string \| null>` | Set a JSON document at path (`JSON.SET`) |
|
|
404
|
+
| `jGet<T>(opts)` | `Promise<T \| null>` | Get a JSON document or path (`JSON.GET`) |
|
|
405
|
+
| `jDelete(opts)` | `Promise<number>` | Delete a JSON path (`JSON.DEL`) |
|
|
406
|
+
| `jNumberIncreaseBy(opts)` | `Promise<string \| null>` | Increment a number at path (`JSON.NUMINCRBY`) |
|
|
407
|
+
| `jStringAppend(opts)` | `Promise<number[] \| null>` | Append to a string at path (`JSON.STRAPPEND`) |
|
|
408
|
+
| `jPush<T>(opts)` | `Promise<number[] \| null>` | Push to an array at path (`JSON.ARRAPPEND`) |
|
|
409
|
+
| `jPop<T>(opts)` | `Promise<T \| null>` | Pop from an array at path (`JSON.ARRPOP`) |
|
|
410
|
+
| **Pub/Sub** | | |
|
|
411
|
+
| `subscribe(opts)` | `void` | Subscribe to a topic. Options: `{ topic }` |
|
|
412
|
+
| `publish<T>(opts)` | `Promise<void>` | Publish to one or more topics with optional compression. Options: `{ topics, payload, useCompress? }` |
|
|
413
|
+
| `unsubscribe(opts)` | `void` | Unsubscribe from a topic. Options: `{ topic }` |
|
|
414
|
+
| **Raw** | | |
|
|
415
|
+
| `execute<R>(command, parameters?)` | `Promise<R>` | Execute any Redis command directly |
|
|
416
|
+
|
|
417
|
+
## Troubleshooting
|
|
418
|
+
|
|
419
|
+
### "[execute] Invalid client to execute | command: ..."
|
|
420
|
+
|
|
421
|
+
**Cause:** `execute()` was called when the ioredis client is `null` or `undefined`. This typically happens if the helper was not properly constructed or the connection was never established.
|
|
422
|
+
|
|
423
|
+
**Fix:** Ensure the helper is instantiated correctly and, if using `autoConnect: false`, call `await redis.connect()` before issuing commands.
|
|
424
|
+
|
|
425
|
+
### "[subscribe] Failed to subscribe to topic: ..."
|
|
426
|
+
|
|
427
|
+
**Cause:** The ioredis `subscribe()` callback received an error. This can happen if the client lost its connection or the Redis server rejected the subscription.
|
|
428
|
+
|
|
429
|
+
**Fix:** Check that the Redis server is reachable and the client is in a valid state. Monitor the `onError` callback for connection issues.
|
|
430
|
+
|
|
431
|
+
### "[unsubscribe] Failed to unsubscribe from topic: ..."
|
|
432
|
+
|
|
433
|
+
**Cause:** The ioredis `unsubscribe()` callback received an error, usually due to a broken connection.
|
|
434
|
+
|
|
435
|
+
**Fix:** Same as above -- verify connectivity and client state.
|
|
436
|
+
|
|
437
|
+
### Connection Refused / Timeout
|
|
438
|
+
|
|
439
|
+
**Symptoms:** `ECONNREFUSED`, connection hangs, or `onError` fires immediately.
|
|
440
|
+
|
|
441
|
+
**Checklist:**
|
|
442
|
+
- Verify Redis is running and reachable at the configured `host:port`
|
|
443
|
+
- Check firewall rules and network access between your application and the Redis server
|
|
444
|
+
- If using `autoConnect: false`, ensure you call `await redis.connect()` before any operations
|
|
445
|
+
- Verify `password` is correct (Redis returns a generic error for auth failure)
|
|
446
|
+
- For clusters, ensure all node addresses are reachable and the cluster is healthy (`redis-cli cluster info`)
|
|
447
|
+
|
|
448
|
+
### Pub/Sub Subscriber Mode Conflicts
|
|
449
|
+
|
|
450
|
+
**Symptoms:** `ERR only (P|S)SUBSCRIBE / (P|S)UNSUBSCRIBE / PING / QUIT / RESET allowed in this context`
|
|
451
|
+
|
|
452
|
+
**Cause:** You called `subscribe()` on a client and then attempted a regular command (`get`, `set`, etc.) on the same client.
|
|
453
|
+
|
|
454
|
+
**Fix:** Use a separate connection for Pub/Sub:
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
const dataClient = new RedisHelper({ name: 'data', host, port, password });
|
|
458
|
+
const subClient = new RedisHelper({ name: 'sub', host, port, password });
|
|
459
|
+
|
|
460
|
+
// Use subClient only for subscribe/unsubscribe
|
|
461
|
+
subClient.subscribe({ topic: 'events' });
|
|
462
|
+
subClient.getClient().on('message', (channel, msg) => { /* ... */ });
|
|
463
|
+
|
|
464
|
+
// Use dataClient for everything else
|
|
465
|
+
await dataClient.set({ key: 'foo', value: 'bar' });
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
### RedisJSON Commands Return Errors
|
|
469
|
+
|
|
470
|
+
**Symptoms:** `ERR unknown command 'JSON.SET'`
|
|
471
|
+
|
|
472
|
+
**Cause:** The RedisJSON module is not installed on your Redis server.
|
|
473
|
+
|
|
474
|
+
**Fix:** Install Redis Stack or the RedisJSON module. See [RedisJSON documentation](https://redis.io/docs/stack/json/).
|
|
475
|
+
|
|
476
|
+
## See Also
|
|
477
|
+
|
|
478
|
+
- **Related Concepts:**
|
|
479
|
+
- [Services](/guides/core-concepts/services) - Using Redis in services
|
|
480
|
+
|
|
481
|
+
- **Other Helpers:**
|
|
482
|
+
- [Helpers Index](../index) - All available helpers
|
|
483
|
+
- [Queue Helper](../queue/) - BullMQ uses Redis as backend
|
|
484
|
+
|
|
485
|
+
- **References:**
|
|
486
|
+
- [DataSources](/references/base/datasources) - Database connections
|
|
487
|
+
|
|
488
|
+
- **External Resources:**
|
|
489
|
+
- [ioredis Documentation](https://github.com/redis/ioredis) - Redis client library
|
|
490
|
+
- [Redis Commands](https://redis.io/commands/) - Redis command reference
|
|
491
|
+
- [RedisJSON](https://redis.io/docs/stack/json/) - JSON module documentation
|
|
492
|
+
|
|
493
|
+
- **Best Practices:**
|
|
494
|
+
- [Performance Optimization](/best-practices/performance-optimization) - Caching strategies
|
|
495
|
+
- [Security Guidelines](/best-practices/security-guidelines) - Redis security
|