@memberjunction/redis-provider 0.0.1 → 5.9.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/README.md +307 -28
- package/dist/RedisLocalStorageProvider.d.ts +491 -0
- package/dist/RedisLocalStorageProvider.d.ts.map +1 -0
- package/dist/RedisLocalStorageProvider.js +740 -0
- package/dist/RedisLocalStorageProvider.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/package.json +30 -7
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Redis-backed implementation of {@link ILocalStorageProvider}.
|
|
3
|
+
*
|
|
4
|
+
* This module provides a drop-in replacement for `InMemoryLocalStorageProvider`
|
|
5
|
+
* that persists data in Redis, enabling:
|
|
6
|
+
*
|
|
7
|
+
* - **Shared caching** across multiple MJAPI server instances (horizontal scaling)
|
|
8
|
+
* - **Persistence** across process restarts
|
|
9
|
+
* - **Native TTL** via Redis `EXPIRE` — expired keys are automatically reclaimed
|
|
10
|
+
*
|
|
11
|
+
* Compatible with any Redis-protocol service: self-hosted Redis, Azure Managed Redis,
|
|
12
|
+
* AWS ElastiCache, Redis Cloud, Upstash, etc.
|
|
13
|
+
*
|
|
14
|
+
* @module @memberjunction/redis-provider
|
|
15
|
+
*/
|
|
16
|
+
import Redis from 'ioredis';
|
|
17
|
+
import type { RedisOptions } from 'ioredis';
|
|
18
|
+
import { ILocalStorageProvider } from '@memberjunction/core';
|
|
19
|
+
import type { CacheChangedEvent } from '@memberjunction/core';
|
|
20
|
+
/**
|
|
21
|
+
* Configuration options for the Redis local storage provider.
|
|
22
|
+
*
|
|
23
|
+
* Accepts either a Redis connection URL string or an `ioredis` options object,
|
|
24
|
+
* plus optional MemberJunction-specific settings.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* // Simple URL connection (works with Azure, AWS, self-hosted)
|
|
29
|
+
* const config: RedisProviderConfig = {
|
|
30
|
+
* url: 'rediss://default:password@my-redis.example.com:6380'
|
|
31
|
+
* };
|
|
32
|
+
*
|
|
33
|
+
* // Full options object with MJ settings
|
|
34
|
+
* const config: RedisProviderConfig = {
|
|
35
|
+
* options: {
|
|
36
|
+
* host: 'localhost',
|
|
37
|
+
* port: 6379,
|
|
38
|
+
* password: 'secret',
|
|
39
|
+
* tls: {},
|
|
40
|
+
* db: 0,
|
|
41
|
+
* },
|
|
42
|
+
* keyPrefix: 'myapp',
|
|
43
|
+
* defaultTTLSeconds: 600,
|
|
44
|
+
* };
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export interface RedisProviderConfig {
|
|
48
|
+
/**
|
|
49
|
+
* Redis connection URL (e.g., `redis://localhost:6379`, `rediss://user:pass@host:6380`).
|
|
50
|
+
* Mutually exclusive with `options`.
|
|
51
|
+
* The `rediss://` scheme enables TLS, which is required for most cloud-hosted Redis services.
|
|
52
|
+
*/
|
|
53
|
+
url?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Full `ioredis` options object for fine-grained connection control.
|
|
56
|
+
* Mutually exclusive with `url`.
|
|
57
|
+
*
|
|
58
|
+
* @see https://github.com/redis/ioredis?tab=readme-ov-file#connect-to-redis
|
|
59
|
+
*/
|
|
60
|
+
options?: RedisOptions;
|
|
61
|
+
/**
|
|
62
|
+
* Optional prefix prepended to all Redis keys. Useful for isolating
|
|
63
|
+
* MemberJunction data in a shared Redis instance.
|
|
64
|
+
*
|
|
65
|
+
* Keys are stored as `{keyPrefix}:{category}:{key}`.
|
|
66
|
+
*
|
|
67
|
+
* @default 'mj'
|
|
68
|
+
*/
|
|
69
|
+
keyPrefix?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Default time-to-live in seconds applied to every `SetItem` call
|
|
72
|
+
* unless overridden by the `ttlSeconds` parameter.
|
|
73
|
+
*
|
|
74
|
+
* Set to `0` or `undefined` to store keys without expiration (persistent).
|
|
75
|
+
*
|
|
76
|
+
* @default undefined (no expiration)
|
|
77
|
+
*/
|
|
78
|
+
defaultTTLSeconds?: number;
|
|
79
|
+
/**
|
|
80
|
+
* Maximum number of connection retry attempts before giving up.
|
|
81
|
+
* Each retry uses exponential backoff (doubling delay up to 30 seconds).
|
|
82
|
+
*
|
|
83
|
+
* @default 10
|
|
84
|
+
*/
|
|
85
|
+
maxRetries?: number;
|
|
86
|
+
/**
|
|
87
|
+
* Whether to log connection events (connect, disconnect, error) via
|
|
88
|
+
* MemberJunction's `LogStatus` / `LogError` functions.
|
|
89
|
+
*
|
|
90
|
+
* @default true
|
|
91
|
+
*/
|
|
92
|
+
enableLogging?: boolean;
|
|
93
|
+
/**
|
|
94
|
+
* Whether to enable Redis pub/sub for cross-server cache invalidation.
|
|
95
|
+
* When enabled, the provider will:
|
|
96
|
+
* - **Publish** a {@link CacheChangedEvent} on every `SetItem`, `Remove`, and `ClearCategory` call
|
|
97
|
+
* - **Subscribe** (via a dedicated second Redis connection) for events from other servers
|
|
98
|
+
* - **Emit** local events so consumers (like `LocalCacheManager`) can dispatch to registered callbacks
|
|
99
|
+
*
|
|
100
|
+
* Pub/sub is **not** started automatically — call {@link RedisLocalStorageProvider.StartListening}
|
|
101
|
+
* after construction to begin subscribing.
|
|
102
|
+
*
|
|
103
|
+
* @default false
|
|
104
|
+
*/
|
|
105
|
+
enablePubSub?: boolean;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Redis-backed implementation of the MemberJunction {@link ILocalStorageProvider} interface.
|
|
109
|
+
*
|
|
110
|
+
* Provides persistent, shared caching for server-side environments using Redis.
|
|
111
|
+
* This is a drop-in replacement for `InMemoryLocalStorageProvider` — all consumers
|
|
112
|
+
* (like `LocalCacheManager`, `ProviderBase` metadata caching, etc.) work without
|
|
113
|
+
* any code changes.
|
|
114
|
+
*
|
|
115
|
+
* ### Key Structure
|
|
116
|
+
*
|
|
117
|
+
* All keys follow the pattern: `{prefix}:{category}:{key}`
|
|
118
|
+
*
|
|
119
|
+
* - **prefix** — configurable, defaults to `"mj"` to isolate MJ data in shared Redis instances
|
|
120
|
+
* - **category** — maps to the MJ cache category (`RunViewCache`, `Metadata`, `DatasetCache`, etc.)
|
|
121
|
+
* - **key** — the original key from the caller
|
|
122
|
+
*
|
|
123
|
+
* Categories are tracked in a Redis Set at `{prefix}:__categories__:{category}` so that
|
|
124
|
+
* `ClearCategory()` and `GetCategoryKeys()` operations are efficient.
|
|
125
|
+
*
|
|
126
|
+
* ### TTL Support
|
|
127
|
+
*
|
|
128
|
+
* Redis has native key expiration. The provider supports TTL at two levels:
|
|
129
|
+
* 1. **`defaultTTLSeconds`** in config — applied to all `SetItem` calls
|
|
130
|
+
* 2. **`ttlSeconds` parameter** on `SetItem` — overrides the default per-call
|
|
131
|
+
*
|
|
132
|
+
* ### Error Handling
|
|
133
|
+
*
|
|
134
|
+
* Redis operations are wrapped in try/catch blocks. Connection errors are logged
|
|
135
|
+
* via `LogError()` but do not throw — the provider gracefully returns `null` for
|
|
136
|
+
* reads and silently skips writes. This prevents a Redis outage from crashing the
|
|
137
|
+
* application. The `ioredis` client handles automatic reconnection.
|
|
138
|
+
*
|
|
139
|
+
* @example
|
|
140
|
+
* ```typescript
|
|
141
|
+
* import { RedisLocalStorageProvider } from '@memberjunction/redis-provider';
|
|
142
|
+
*
|
|
143
|
+
* const provider = new RedisLocalStorageProvider({
|
|
144
|
+
* url: 'redis://localhost:6379',
|
|
145
|
+
* defaultTTLSeconds: 300 // 5-minute default TTL
|
|
146
|
+
* });
|
|
147
|
+
*
|
|
148
|
+
* await provider.SetItem('user:123', JSON.stringify(userData), 'UserCache');
|
|
149
|
+
* const cached = await provider.GetItem('user:123', 'UserCache');
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
export declare class RedisLocalStorageProvider implements ILocalStorageProvider {
|
|
153
|
+
private _client;
|
|
154
|
+
private _keyPrefix;
|
|
155
|
+
private _defaultTTLSeconds;
|
|
156
|
+
private _enableLogging;
|
|
157
|
+
private _connected;
|
|
158
|
+
private _enablePubSub;
|
|
159
|
+
private _subscriber;
|
|
160
|
+
private _pubSubChannel;
|
|
161
|
+
private _eventEmitter;
|
|
162
|
+
private _subscriberConnected;
|
|
163
|
+
private _config;
|
|
164
|
+
/**
|
|
165
|
+
* Creates a new Redis local storage provider and establishes a connection.
|
|
166
|
+
*
|
|
167
|
+
* The constructor sets up the `ioredis` client with automatic reconnection,
|
|
168
|
+
* error handling, and optional logging. The client connects lazily on the
|
|
169
|
+
* first command, so construction itself does not block.
|
|
170
|
+
*
|
|
171
|
+
* @param config - Redis connection and behavior configuration.
|
|
172
|
+
* At minimum, provide either `url` or `options`.
|
|
173
|
+
* If neither is provided, connects to `localhost:6379`.
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* // Connect to local Redis
|
|
178
|
+
* const provider = new RedisLocalStorageProvider({});
|
|
179
|
+
*
|
|
180
|
+
* // Connect to Azure Managed Redis with TLS
|
|
181
|
+
* const provider = new RedisLocalStorageProvider({
|
|
182
|
+
* url: 'rediss://default:ACCESS_KEY@myredis.redis.cache.windows.net:6380',
|
|
183
|
+
* defaultTTLSeconds: 600
|
|
184
|
+
* });
|
|
185
|
+
*
|
|
186
|
+
* // Connect to AWS ElastiCache
|
|
187
|
+
* const provider = new RedisLocalStorageProvider({
|
|
188
|
+
* options: {
|
|
189
|
+
* host: 'my-cluster.abc123.use1.cache.amazonaws.com',
|
|
190
|
+
* port: 6379,
|
|
191
|
+
* tls: {}
|
|
192
|
+
* }
|
|
193
|
+
* });
|
|
194
|
+
* ```
|
|
195
|
+
*/
|
|
196
|
+
constructor(config?: RedisProviderConfig);
|
|
197
|
+
/**
|
|
198
|
+
* Exponential backoff retry strategy for Redis connections.
|
|
199
|
+
* Doubles the delay on each attempt (capped at 30 seconds) and gives up
|
|
200
|
+
* after `maxRetries` attempts.
|
|
201
|
+
*
|
|
202
|
+
* @param times - Current retry attempt number (1-based)
|
|
203
|
+
* @param maxRetries - Maximum number of retries before giving up
|
|
204
|
+
* @returns Delay in milliseconds, or `null` to stop retrying
|
|
205
|
+
* @internal
|
|
206
|
+
*/
|
|
207
|
+
private retryStrategy;
|
|
208
|
+
/**
|
|
209
|
+
* Registers event handlers on the ioredis client for logging connection
|
|
210
|
+
* lifecycle events (connect, ready, close, error, reconnecting).
|
|
211
|
+
* @internal
|
|
212
|
+
*/
|
|
213
|
+
private setupEventHandlers;
|
|
214
|
+
/**
|
|
215
|
+
* Builds the full Redis key from a category and key name.
|
|
216
|
+
*
|
|
217
|
+
* Format: `{prefix}:{category}:{key}`
|
|
218
|
+
*
|
|
219
|
+
* @param key - The storage key
|
|
220
|
+
* @param category - The category for key isolation
|
|
221
|
+
* @returns The fully-qualified Redis key string
|
|
222
|
+
* @internal
|
|
223
|
+
*/
|
|
224
|
+
private buildKey;
|
|
225
|
+
/**
|
|
226
|
+
* Builds the Redis Set key used to track all keys in a category.
|
|
227
|
+
*
|
|
228
|
+
* Format: `{prefix}:__categories__:{category}`
|
|
229
|
+
*
|
|
230
|
+
* @param category - The category name
|
|
231
|
+
* @returns The Redis key for the category's membership set
|
|
232
|
+
* @internal
|
|
233
|
+
*/
|
|
234
|
+
private buildCategorySetKey;
|
|
235
|
+
/**
|
|
236
|
+
* Retrieves a value from Redis by key and optional category.
|
|
237
|
+
*
|
|
238
|
+
* @param key - The key to look up
|
|
239
|
+
* @param category - Optional category for key isolation (defaults to `"default"`)
|
|
240
|
+
* @returns The stored string value, or `null` if the key doesn't exist or Redis is unavailable
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* const value = await provider.GetItem('entity-metadata', 'Metadata');
|
|
245
|
+
* if (value) {
|
|
246
|
+
* const metadata = JSON.parse(value);
|
|
247
|
+
* }
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
GetItem(key: string, category?: string): Promise<string | null>;
|
|
251
|
+
/**
|
|
252
|
+
* Stores a value in Redis under the given key and optional category.
|
|
253
|
+
*
|
|
254
|
+
* If a `ttlSeconds` is provided, the key will automatically expire after that
|
|
255
|
+
* duration. Otherwise, the configured `defaultTTLSeconds` is used. If neither
|
|
256
|
+
* is set, the key persists indefinitely.
|
|
257
|
+
*
|
|
258
|
+
* The key is also added to a Redis Set that tracks all keys in the category,
|
|
259
|
+
* enabling efficient `ClearCategory()` and `GetCategoryKeys()` operations.
|
|
260
|
+
*
|
|
261
|
+
* @param key - The key to store under
|
|
262
|
+
* @param value - The string value to store
|
|
263
|
+
* @param category - Optional category for key isolation (defaults to `"default"`)
|
|
264
|
+
* @param ttlSeconds - Optional time-to-live in seconds. Overrides `defaultTTLSeconds` from config.
|
|
265
|
+
*
|
|
266
|
+
* @example
|
|
267
|
+
* ```typescript
|
|
268
|
+
* // Store with default TTL
|
|
269
|
+
* await provider.SetItem('view:users', JSON.stringify(results), 'RunViewCache');
|
|
270
|
+
*
|
|
271
|
+
* // Store with explicit 10-minute TTL
|
|
272
|
+
* await provider.SetItem('view:users', JSON.stringify(results), 'RunViewCache', 600);
|
|
273
|
+
* ```
|
|
274
|
+
*/
|
|
275
|
+
SetItem(key: string, value: string, category?: string, ttlSeconds?: number): Promise<void>;
|
|
276
|
+
/**
|
|
277
|
+
* Removes a key from Redis and from its category tracking set.
|
|
278
|
+
*
|
|
279
|
+
* @param key - The key to remove
|
|
280
|
+
* @param category - Optional category for key isolation (defaults to `"default"`)
|
|
281
|
+
*
|
|
282
|
+
* @example
|
|
283
|
+
* ```typescript
|
|
284
|
+
* await provider.Remove('view:users', 'RunViewCache');
|
|
285
|
+
* ```
|
|
286
|
+
*/
|
|
287
|
+
Remove(key: string, category?: string): Promise<void>;
|
|
288
|
+
/**
|
|
289
|
+
* Clears all keys belonging to a specific category.
|
|
290
|
+
*
|
|
291
|
+
* Uses the category tracking Set to find all member keys, deletes them
|
|
292
|
+
* in a single pipeline call, then removes the tracking Set itself.
|
|
293
|
+
*
|
|
294
|
+
* @param category - The category to clear. If empty, clears the `"default"` category.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* ```typescript
|
|
298
|
+
* // Clear all cached RunView results
|
|
299
|
+
* await provider.ClearCategory('RunViewCache');
|
|
300
|
+
* ```
|
|
301
|
+
*/
|
|
302
|
+
ClearCategory(category: string): Promise<void>;
|
|
303
|
+
/**
|
|
304
|
+
* Returns all keys belonging to a specific category.
|
|
305
|
+
*
|
|
306
|
+
* Reads from the category tracking Set, so the result reflects keys
|
|
307
|
+
* that were added via `SetItem` (some may have expired via TTL but
|
|
308
|
+
* will still appear in the set until cleaned up).
|
|
309
|
+
*
|
|
310
|
+
* @param category - The category to list keys from
|
|
311
|
+
* @returns Array of original key names (without the Redis prefix/category prefix)
|
|
312
|
+
*
|
|
313
|
+
* @example
|
|
314
|
+
* ```typescript
|
|
315
|
+
* const keys = await provider.GetCategoryKeys('RunViewCache');
|
|
316
|
+
* console.log(`${keys.length} cached views`);
|
|
317
|
+
* ```
|
|
318
|
+
*/
|
|
319
|
+
GetCategoryKeys(category: string): Promise<string[]>;
|
|
320
|
+
/**
|
|
321
|
+
* Whether the Redis client currently has an active connection.
|
|
322
|
+
*
|
|
323
|
+
* Note: `ioredis` automatically reconnects on failure, so a `false` value
|
|
324
|
+
* here is usually transient. The provider continues to accept commands
|
|
325
|
+
* (they queue until reconnection succeeds or retry limit is hit).
|
|
326
|
+
*/
|
|
327
|
+
get IsConnected(): boolean;
|
|
328
|
+
/**
|
|
329
|
+
* Returns the underlying `ioredis` client instance for advanced operations.
|
|
330
|
+
*
|
|
331
|
+
* Use with caution — direct client access bypasses key prefixing and
|
|
332
|
+
* category tracking. Prefer the `ILocalStorageProvider` methods for
|
|
333
|
+
* standard operations.
|
|
334
|
+
*
|
|
335
|
+
* @example
|
|
336
|
+
* ```typescript
|
|
337
|
+
* // Use for Redis-specific commands like pub/sub, streams, etc.
|
|
338
|
+
* const client = provider.Client;
|
|
339
|
+
* await client.publish('cache-invalidation', 'entity:Users');
|
|
340
|
+
* ```
|
|
341
|
+
*/
|
|
342
|
+
get Client(): Redis;
|
|
343
|
+
/**
|
|
344
|
+
* Gracefully disconnects from Redis.
|
|
345
|
+
*
|
|
346
|
+
* Sends a `QUIT` command and waits for pending replies. After calling this
|
|
347
|
+
* method, the provider should not be used for further operations.
|
|
348
|
+
*
|
|
349
|
+
* Call this during application shutdown to ensure clean disconnection.
|
|
350
|
+
*
|
|
351
|
+
* @example
|
|
352
|
+
* ```typescript
|
|
353
|
+
* // During application shutdown
|
|
354
|
+
* process.on('SIGTERM', async () => {
|
|
355
|
+
* await redisProvider.Disconnect();
|
|
356
|
+
* process.exit(0);
|
|
357
|
+
* });
|
|
358
|
+
* ```
|
|
359
|
+
*/
|
|
360
|
+
Disconnect(): Promise<void>;
|
|
361
|
+
/**
|
|
362
|
+
* Checks if a key exists in the specified category.
|
|
363
|
+
*
|
|
364
|
+
* This is more efficient than `GetItem()` when you only need to check
|
|
365
|
+
* existence without retrieving the value (avoids transferring the value
|
|
366
|
+
* over the network).
|
|
367
|
+
*
|
|
368
|
+
* @param key - The key to check
|
|
369
|
+
* @param category - Optional category for key isolation (defaults to `"default"`)
|
|
370
|
+
* @returns `true` if the key exists and has not expired
|
|
371
|
+
*
|
|
372
|
+
* @example
|
|
373
|
+
* ```typescript
|
|
374
|
+
* if (await provider.Exists('view:users', 'RunViewCache')) {
|
|
375
|
+
* // Use cached value
|
|
376
|
+
* }
|
|
377
|
+
* ```
|
|
378
|
+
*/
|
|
379
|
+
Exists(key: string, category?: string): Promise<boolean>;
|
|
380
|
+
/**
|
|
381
|
+
* Returns the remaining time-to-live (in seconds) for a key.
|
|
382
|
+
*
|
|
383
|
+
* @param key - The key to check
|
|
384
|
+
* @param category - Optional category for key isolation (defaults to `"default"`)
|
|
385
|
+
* @returns TTL in seconds, `-1` if no expiration is set, `-2` if the key doesn't exist,
|
|
386
|
+
* or `null` if Redis is unavailable
|
|
387
|
+
*
|
|
388
|
+
* @example
|
|
389
|
+
* ```typescript
|
|
390
|
+
* const ttl = await provider.GetTTL('view:users', 'RunViewCache');
|
|
391
|
+
* if (ttl !== null && ttl > 0) {
|
|
392
|
+
* console.log(`Key expires in ${ttl} seconds`);
|
|
393
|
+
* }
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
396
|
+
GetTTL(key: string, category?: string): Promise<number | null>;
|
|
397
|
+
/**
|
|
398
|
+
* Pings the Redis server to verify connectivity.
|
|
399
|
+
*
|
|
400
|
+
* Useful for health checks and connection validation.
|
|
401
|
+
*
|
|
402
|
+
* @returns `true` if the server responds with `PONG`, `false` otherwise
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```typescript
|
|
406
|
+
* const healthy = await provider.Ping();
|
|
407
|
+
* if (!healthy) {
|
|
408
|
+
* console.error('Redis is unreachable');
|
|
409
|
+
* }
|
|
410
|
+
* ```
|
|
411
|
+
*/
|
|
412
|
+
Ping(): Promise<boolean>;
|
|
413
|
+
/**
|
|
414
|
+
* Starts listening for cache change events from other server instances.
|
|
415
|
+
* Creates a dedicated Redis connection for pub/sub (required by Redis protocol —
|
|
416
|
+
* a client in subscribe mode cannot execute other commands).
|
|
417
|
+
*
|
|
418
|
+
* Must be called explicitly after construction. No-op if `enablePubSub` is `false`
|
|
419
|
+
* in the config, or if already listening.
|
|
420
|
+
*
|
|
421
|
+
* @example
|
|
422
|
+
* ```typescript
|
|
423
|
+
* const provider = new RedisLocalStorageProvider({
|
|
424
|
+
* url: 'redis://localhost:6379',
|
|
425
|
+
* enablePubSub: true
|
|
426
|
+
* });
|
|
427
|
+
* await provider.StartListening();
|
|
428
|
+
*
|
|
429
|
+
* // Register for change events
|
|
430
|
+
* provider.OnCacheChanged((event) => {
|
|
431
|
+
* console.log(`Key "${event.CacheKey}" changed by server ${event.SourceServerId}`);
|
|
432
|
+
* });
|
|
433
|
+
* ```
|
|
434
|
+
*/
|
|
435
|
+
StartListening(): Promise<void>;
|
|
436
|
+
/**
|
|
437
|
+
* Creates the subscriber Redis client, mirroring the main client's connection config.
|
|
438
|
+
* @internal
|
|
439
|
+
*/
|
|
440
|
+
private createSubscriberClient;
|
|
441
|
+
/**
|
|
442
|
+
* Sets up event handlers on the subscriber client for logging.
|
|
443
|
+
* @internal
|
|
444
|
+
*/
|
|
445
|
+
private setupSubscriberEventHandlers;
|
|
446
|
+
/**
|
|
447
|
+
* Handles an incoming pub/sub message. Parses the {@link CacheChangedEvent},
|
|
448
|
+
* filters out self-originated events, and emits to local listeners.
|
|
449
|
+
* @internal
|
|
450
|
+
*/
|
|
451
|
+
private handlePubSubMessage;
|
|
452
|
+
/**
|
|
453
|
+
* Publishes a cache change event to Redis pub/sub. Called internally by
|
|
454
|
+
* `SetItem`, `Remove`, and `ClearCategory`. No-op if pub/sub is disabled.
|
|
455
|
+
*
|
|
456
|
+
* @param cacheKey - The cache key that changed
|
|
457
|
+
* @param category - The storage category
|
|
458
|
+
* @param action - What happened ('set', 'removed', 'category_cleared')
|
|
459
|
+
* @param data - The new value (only for 'set' actions)
|
|
460
|
+
* @internal
|
|
461
|
+
*/
|
|
462
|
+
private publishChange;
|
|
463
|
+
/**
|
|
464
|
+
* Registers a callback for cache change events from other servers.
|
|
465
|
+
* The callback fires whenever another server instance modifies a cached entry
|
|
466
|
+
* (via `SetItem`, `Remove`, or `ClearCategory`).
|
|
467
|
+
*
|
|
468
|
+
* Events from this server instance (identified by {@link MJGlobal.ProcessUUID})
|
|
469
|
+
* are automatically filtered out.
|
|
470
|
+
*
|
|
471
|
+
* @param callback - Function invoked with the {@link CacheChangedEvent}
|
|
472
|
+
* @returns A function that, when called, removes this callback registration
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* ```typescript
|
|
476
|
+
* const unsubscribe = provider.OnCacheChanged((event) => {
|
|
477
|
+
* // Dispatch to LocalCacheManager for callback routing
|
|
478
|
+
* LocalCacheManager.Instance.DispatchCacheChange(event);
|
|
479
|
+
* });
|
|
480
|
+
*
|
|
481
|
+
* // Later, on shutdown:
|
|
482
|
+
* unsubscribe();
|
|
483
|
+
* ```
|
|
484
|
+
*/
|
|
485
|
+
OnCacheChanged(callback: (event: CacheChangedEvent) => void): () => void;
|
|
486
|
+
/**
|
|
487
|
+
* Whether the pub/sub subscriber connection is currently active.
|
|
488
|
+
*/
|
|
489
|
+
get IsSubscriberConnected(): boolean;
|
|
490
|
+
}
|
|
491
|
+
//# sourceMappingURL=RedisLocalStorageProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RedisLocalStorageProvider.d.ts","sourceRoot":"","sources":["../src/RedisLocalStorageProvider.ts"],"names":[],"mappings":"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"}
|