ioredis-toolkit 0.0.9 → 0.5.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/CHANGELOG.md +67 -0
- package/LICENSE +1 -1
- package/README.md +68 -1058
- package/dist/cache/cache.d.ts +30 -0
- package/dist/cache/cache.d.ts.map +1 -0
- package/dist/cache/cache.js +59 -0
- package/dist/cache/cache.js.map +1 -0
- package/dist/cache/config.d.ts +12 -0
- package/dist/cache/config.d.ts.map +1 -0
- package/dist/cache/config.js +13 -0
- package/dist/cache/config.js.map +1 -0
- package/dist/cache/types.d.ts +32 -0
- package/dist/cache/types.d.ts.map +1 -0
- package/dist/cache/types.js +5 -0
- package/dist/cache/types.js.map +1 -0
- package/dist/index.d.ts +43 -51
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -44
- package/dist/index.js.map +1 -0
- package/dist/lock/config.d.ts +12 -0
- package/dist/lock/config.d.ts.map +1 -0
- package/dist/lock/config.js +8 -0
- package/dist/lock/config.js.map +1 -0
- package/dist/lock/lock.d.ts +20 -0
- package/dist/lock/lock.d.ts.map +1 -0
- package/dist/lock/lock.js +44 -0
- package/dist/lock/lock.js.map +1 -0
- package/dist/lock/types.d.ts +19 -0
- package/dist/lock/types.d.ts.map +1 -0
- package/dist/lock/types.js +2 -0
- package/dist/lock/types.js.map +1 -0
- package/dist/modules-config.d.ts +3 -0
- package/dist/modules-config.d.ts.map +1 -0
- package/dist/modules-config.js +2 -0
- package/dist/modules-config.js.map +1 -0
- package/dist/pubsub/config.d.ts +11 -0
- package/dist/pubsub/config.d.ts.map +1 -0
- package/dist/pubsub/config.js +6 -0
- package/dist/pubsub/config.js.map +1 -0
- package/dist/pubsub/pubsub.d.ts +20 -0
- package/dist/pubsub/pubsub.d.ts.map +1 -0
- package/dist/pubsub/pubsub.js +54 -0
- package/dist/pubsub/pubsub.js.map +1 -0
- package/dist/pubsub/types.d.ts +24 -0
- package/dist/pubsub/types.d.ts.map +1 -0
- package/dist/pubsub/types.js +2 -0
- package/dist/pubsub/types.js.map +1 -0
- package/dist/rate-limit/config.d.ts +12 -0
- package/dist/rate-limit/config.d.ts.map +1 -0
- package/dist/rate-limit/config.js +6 -0
- package/dist/rate-limit/config.js.map +1 -0
- package/dist/rate-limit/rate-limiter.d.ts +18 -0
- package/dist/rate-limit/rate-limiter.d.ts.map +1 -0
- package/dist/rate-limit/rate-limiter.js +37 -0
- package/dist/rate-limit/rate-limiter.js.map +1 -0
- package/dist/rate-limit/types.d.ts +27 -0
- package/dist/rate-limit/types.d.ts.map +1 -0
- package/dist/rate-limit/types.js +2 -0
- package/dist/rate-limit/types.js.map +1 -0
- package/dist/redis/client-facade.d.ts +77 -0
- package/dist/redis/client-facade.d.ts.map +1 -0
- package/dist/redis/client-facade.js +102 -0
- package/dist/redis/client-facade.js.map +1 -0
- package/dist/redis/client.d.ts +10 -0
- package/dist/redis/client.d.ts.map +1 -0
- package/dist/redis/client.js +29 -0
- package/dist/redis/client.js.map +1 -0
- package/dist/redis/cluster.d.ts +7 -0
- package/dist/redis/cluster.d.ts.map +1 -0
- package/dist/redis/cluster.js +47 -0
- package/dist/redis/cluster.js.map +1 -0
- package/dist/redis/config.d.ts +39 -0
- package/dist/redis/config.d.ts.map +1 -0
- package/dist/redis/config.js +52 -0
- package/dist/redis/config.js.map +1 -0
- package/dist/redis/errors.d.ts +5 -0
- package/dist/redis/errors.d.ts.map +1 -0
- package/dist/redis/errors.js +5 -0
- package/dist/redis/errors.js.map +1 -0
- package/dist/redis/types.d.ts +135 -0
- package/dist/redis/types.d.ts.map +1 -0
- package/dist/redis/types.js +2 -0
- package/dist/redis/types.js.map +1 -0
- package/dist/redis/wrapper.d.ts +88 -0
- package/dist/redis/wrapper.d.ts.map +1 -0
- package/dist/redis/wrapper.js +206 -0
- package/dist/redis/wrapper.js.map +1 -0
- package/dist/session/config.d.ts +47 -0
- package/dist/session/config.d.ts.map +1 -0
- package/dist/session/config.js +101 -0
- package/dist/session/config.js.map +1 -0
- package/dist/session/cookie.d.ts +16 -0
- package/dist/session/cookie.d.ts.map +1 -0
- package/dist/session/cookie.js +28 -0
- package/dist/session/cookie.js.map +1 -0
- package/dist/session/errors.d.ts +56 -0
- package/dist/session/errors.d.ts.map +1 -0
- package/dist/session/errors.js +58 -0
- package/dist/session/errors.js.map +1 -0
- package/dist/session/factory.d.ts +21 -0
- package/dist/session/factory.d.ts.map +1 -0
- package/dist/session/factory.js +30 -0
- package/dist/session/factory.js.map +1 -0
- package/dist/session/health.d.ts +12 -0
- package/dist/session/health.d.ts.map +1 -0
- package/dist/session/health.js +23 -0
- package/dist/session/health.js.map +1 -0
- package/dist/session/keys.d.ts +23 -0
- package/dist/session/keys.d.ts.map +1 -0
- package/dist/session/keys.js +27 -0
- package/dist/session/keys.js.map +1 -0
- package/dist/session/manager.d.ts +34 -0
- package/dist/session/manager.d.ts.map +1 -0
- package/dist/session/manager.js +31 -0
- package/dist/session/manager.js.map +1 -0
- package/dist/session/metrics.d.ts +11 -0
- package/dist/session/metrics.d.ts.map +1 -0
- package/dist/session/metrics.js +10 -0
- package/dist/session/metrics.js.map +1 -0
- package/dist/session/repository.d.ts +49 -0
- package/dist/session/repository.d.ts.map +1 -0
- package/dist/session/repository.js +203 -0
- package/dist/session/repository.js.map +1 -0
- package/dist/session/revocation.d.ts +22 -0
- package/dist/session/revocation.d.ts.map +1 -0
- package/dist/session/revocation.js +41 -0
- package/dist/session/revocation.js.map +1 -0
- package/dist/session/script-sources.d.ts +11 -0
- package/dist/session/script-sources.d.ts.map +1 -0
- package/dist/session/script-sources.js +140 -0
- package/dist/session/script-sources.js.map +1 -0
- package/dist/session/scripts.d.ts +15 -0
- package/dist/session/scripts.d.ts.map +1 -0
- package/dist/session/scripts.js +41 -0
- package/dist/session/scripts.js.map +1 -0
- package/dist/session/serializer.d.ts +12 -0
- package/dist/session/serializer.d.ts.map +1 -0
- package/dist/session/serializer.js +77 -0
- package/dist/session/serializer.js.map +1 -0
- package/dist/session/service.d.ts +48 -0
- package/dist/session/service.d.ts.map +1 -0
- package/dist/session/service.js +235 -0
- package/dist/session/service.js.map +1 -0
- package/dist/session/token.d.ts +16 -0
- package/dist/session/token.d.ts.map +1 -0
- package/dist/session/token.js +32 -0
- package/dist/session/token.js.map +1 -0
- package/dist/session/types.d.ts +134 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +2 -0
- package/dist/session/types.js.map +1 -0
- package/dist/streams/config.d.ts +12 -0
- package/dist/streams/config.d.ts.map +1 -0
- package/dist/streams/config.js +6 -0
- package/dist/streams/config.js.map +1 -0
- package/dist/streams/streams.d.ts +24 -0
- package/dist/streams/streams.d.ts.map +1 -0
- package/dist/streams/streams.js +55 -0
- package/dist/streams/streams.js.map +1 -0
- package/dist/streams/types.d.ts +32 -0
- package/dist/streams/types.d.ts.map +1 -0
- package/dist/streams/types.js +2 -0
- package/dist/streams/types.js.map +1 -0
- package/docs/ACCEPTANCE-REPORT.md +70 -0
- package/docs/ARCHITECTURE.md +61 -0
- package/docs/CAPACITY.md +33 -0
- package/docs/DEPLOYMENT.md +22 -0
- package/docs/README-API.md +15 -0
- package/docs/STATE-MACHINE.md +38 -0
- package/docs/TESTING.md +37 -0
- package/docs/THREAT-MODEL.md +23 -0
- package/docs/TYPE-SAFETY.md +34 -0
- package/docs/modules/cache/README.md +7 -0
- package/docs/modules/cache/usage.md +156 -0
- package/docs/modules/lock/README.md +7 -0
- package/docs/modules/lock/usage.md +105 -0
- package/docs/modules/pubsub/README.md +7 -0
- package/docs/modules/pubsub/usage.md +106 -0
- package/docs/modules/rate-limit/README.md +7 -0
- package/docs/modules/rate-limit/usage.md +100 -0
- package/docs/modules/sessions/README.md +7 -0
- package/docs/modules/sessions/usage.md +262 -0
- package/docs/modules/streams/README.md +7 -0
- package/docs/modules/streams/usage.md +141 -0
- package/package.json +50 -60
- package/src/scripts/cleanup-index.lua +4 -0
- package/src/scripts/conditional-update.lua +21 -0
- package/src/scripts/consume-session.lua +21 -0
- package/src/scripts/create-session.lua +28 -0
- package/src/scripts/delete.lua +2 -0
- package/src/scripts/destroy-user.lua +13 -0
- package/src/scripts/enforce-limit.lua +17 -0
- package/src/scripts/revoke-session.lua +13 -0
- package/src/scripts/rotate.lua +24 -0
- package/src/scripts/touch-session.lua +28 -0
- package/src/scripts/update-session.lua +18 -0
- package/dist/cache.d.ts +0 -796
- package/dist/cache.js +0 -1120
- package/dist/client.d.ts +0 -284
- package/dist/client.js +0 -1114
- package/dist/cluster-slot.d.ts +0 -4
- package/dist/cluster-slot.js +0 -31
- package/dist/cluster.d.ts +0 -79
- package/dist/cluster.js +0 -156
- package/dist/errors.d.ts +0 -30
- package/dist/errors.js +0 -63
- package/dist/health.d.ts +0 -180
- package/dist/health.js +0 -239
- package/dist/lock.d.ts +0 -248
- package/dist/lock.js +0 -397
- package/dist/logger.d.ts +0 -12
- package/dist/logger.js +0 -40
- package/dist/pubsub.d.ts +0 -423
- package/dist/pubsub.js +0 -537
- package/dist/ratelimiter.d.ts +0 -441
- package/dist/ratelimiter.js +0 -539
- package/dist/session/index.d.ts +0 -23
- package/dist/session/index.js +0 -16
- package/dist/session/revocation-store.d.ts +0 -176
- package/dist/session/revocation-store.js +0 -318
- package/dist/session/scripts/cleanup-index.lua +0 -21
- package/dist/session/scripts/conditional-update-encrypted.lua +0 -60
- package/dist/session/scripts/conditional-update.lua +0 -63
- package/dist/session/scripts/create.lua +0 -83
- package/dist/session/scripts/delete-by-user.lua +0 -29
- package/dist/session/scripts/delete.lua +0 -15
- package/dist/session/scripts/enforce-limit.lua +0 -38
- package/dist/session/scripts/revoke.lua +0 -61
- package/dist/session/scripts/rotate-encrypted.lua +0 -110
- package/dist/session/scripts/rotate.lua +0 -122
- package/dist/session/scripts/touch-encrypted.lua +0 -89
- package/dist/session/scripts/touch.lua +0 -72
- package/dist/session/scripts/validate.lua +0 -90
- package/dist/session/session-circuit-breaker.d.ts +0 -42
- package/dist/session/session-circuit-breaker.js +0 -129
- package/dist/session/session-config.d.ts +0 -335
- package/dist/session/session-config.js +0 -162
- package/dist/session/session-cookie.d.ts +0 -72
- package/dist/session/session-cookie.js +0 -101
- package/dist/session/session-encryption.d.ts +0 -87
- package/dist/session/session-encryption.js +0 -139
- package/dist/session/session-errors.d.ts +0 -85
- package/dist/session/session-errors.js +0 -145
- package/dist/session/session-health.d.ts +0 -38
- package/dist/session/session-health.js +0 -60
- package/dist/session/session-keys.d.ts +0 -51
- package/dist/session/session-keys.js +0 -113
- package/dist/session/session-manager.d.ts +0 -73
- package/dist/session/session-manager.js +0 -94
- package/dist/session/session-metrics.d.ts +0 -33
- package/dist/session/session-metrics.js +0 -112
- package/dist/session/session-repository.d.ts +0 -161
- package/dist/session/session-repository.js +0 -683
- package/dist/session/session-scripts.d.ts +0 -36
- package/dist/session/session-scripts.js +0 -130
- package/dist/session/session-serializer.d.ts +0 -42
- package/dist/session/session-serializer.js +0 -248
- package/dist/session/session-service.d.ts +0 -104
- package/dist/session/session-service.js +0 -611
- package/dist/session/session-token.d.ts +0 -38
- package/dist/session/session-token.js +0 -86
- package/dist/session/session-types.d.ts +0 -253
- package/dist/session/session-types.js +0 -16
- package/dist/types.d.ts +0 -924
- package/dist/types.js +0 -151
- package/dist/utils/deepmerge.d.ts +0 -9
- package/dist/utils/deepmerge.js +0 -61
package/dist/health.js
DELETED
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
import { defaultLogger } from './logger.js';
|
|
2
|
-
export class HealthChecker {
|
|
3
|
-
client;
|
|
4
|
-
logger;
|
|
5
|
-
timer = null;
|
|
6
|
-
callbacks = [];
|
|
7
|
-
lastStatus = null;
|
|
8
|
-
/**
|
|
9
|
-
* Creates a health checker instance.
|
|
10
|
-
*
|
|
11
|
-
* @param client - The underlying {@link RedisClientWrapper}.
|
|
12
|
-
* @param logger - Optional pino-compatible logger; defaults to `console`.
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* ```ts
|
|
16
|
-
* const health = new HealthChecker(client);
|
|
17
|
-
* ```
|
|
18
|
-
*/
|
|
19
|
-
constructor(client, logger = defaultLogger) {
|
|
20
|
-
this.client = client;
|
|
21
|
-
this.logger = logger.child({ component: 'HealthChecker' });
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Starts periodic health checks.
|
|
25
|
-
*
|
|
26
|
-
* **Behavior:**
|
|
27
|
-
* - If a timer is already running, it is cleared and replaced with the new interval.
|
|
28
|
-
* - Health checks run at the specified `interval` in milliseconds.
|
|
29
|
-
* - Each check runs asynchronously; errors are logged but do not stop the interval.
|
|
30
|
-
* - The first check runs immediately when `start()` is called (depending on setInterval timing).
|
|
31
|
-
*
|
|
32
|
-
* **Parameters:**
|
|
33
|
-
* - `interval` - Check interval in milliseconds. Default: `10000` (10 seconds).
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```ts
|
|
37
|
-
* // Check every 5 seconds
|
|
38
|
-
* health.start(5000);
|
|
39
|
-
*
|
|
40
|
-
* // Check every 30 seconds (default)
|
|
41
|
-
* health.start();
|
|
42
|
-
* ```
|
|
43
|
-
*
|
|
44
|
-
* @returns `void`
|
|
45
|
-
*/
|
|
46
|
-
start(interval = 10000) {
|
|
47
|
-
if (this.timer) {
|
|
48
|
-
clearInterval(this.timer);
|
|
49
|
-
}
|
|
50
|
-
this.timer = setInterval(() => {
|
|
51
|
-
this.check().catch((error) => {
|
|
52
|
-
this.logger.error('Health check failed:', error);
|
|
53
|
-
});
|
|
54
|
-
}, interval);
|
|
55
|
-
this.logger.info(`Health checker started (interval: ${interval}ms)`);
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Stops the health checker.
|
|
59
|
-
*
|
|
60
|
-
* **Behavior:**
|
|
61
|
-
* - Clears the internal timer, stopping further health checks.
|
|
62
|
-
* - Logs a warning if no timer was active.
|
|
63
|
-
*
|
|
64
|
-
* @example
|
|
65
|
-
* ```ts
|
|
66
|
-
* health.stop();
|
|
67
|
-
* ```
|
|
68
|
-
*
|
|
69
|
-
* @returns `void`
|
|
70
|
-
*/
|
|
71
|
-
stop() {
|
|
72
|
-
if (this.timer) {
|
|
73
|
-
clearInterval(this.timer);
|
|
74
|
-
this.timer = null;
|
|
75
|
-
this.logger.info('Health checker stopped');
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Runs a single health check.
|
|
80
|
-
*
|
|
81
|
-
* **Behavior:**
|
|
82
|
-
* - Performs a PING command to verify Redis connectivity.
|
|
83
|
-
* - Attempts to fetch Redis INFO for additional details (connections, memory).
|
|
84
|
-
* In cluster mode, INFO may not be available and is silently ignored.
|
|
85
|
-
* - Measures latency of the PING command.
|
|
86
|
-
* - Updates the internal `lastStatus` and notifies all registered callbacks.
|
|
87
|
-
*
|
|
88
|
-
* **Returns:**
|
|
89
|
-
* - A {@link HealthStatus} object with the current health state.
|
|
90
|
-
*
|
|
91
|
-
* **Example:**
|
|
92
|
-
* ```ts
|
|
93
|
-
* const status = await health.check();
|
|
94
|
-
* console.log(status.healthy, status.latency);
|
|
95
|
-
* // healthy === true, latency === 1.2 (ms)
|
|
96
|
-
* ```
|
|
97
|
-
*
|
|
98
|
-
* **Parameters:**
|
|
99
|
-
* - None
|
|
100
|
-
*
|
|
101
|
-
* @returns Current health status.
|
|
102
|
-
*/
|
|
103
|
-
async check() {
|
|
104
|
-
const start = Date.now();
|
|
105
|
-
const details = {
|
|
106
|
-
ping: false,
|
|
107
|
-
};
|
|
108
|
-
try {
|
|
109
|
-
const ping = await this.client.ping();
|
|
110
|
-
details.ping = ping;
|
|
111
|
-
// Try to get some info
|
|
112
|
-
try {
|
|
113
|
-
const info = await this.client.raw.info();
|
|
114
|
-
const connections = info.match(/connected_clients:(\d+)/)?.[1];
|
|
115
|
-
const memory = info.match(/used_memory_human:([^\n]+)/)?.[1];
|
|
116
|
-
if (connections)
|
|
117
|
-
details.connections = parseInt(connections, 10);
|
|
118
|
-
if (memory)
|
|
119
|
-
details.memory = memory.trim();
|
|
120
|
-
}
|
|
121
|
-
catch {
|
|
122
|
-
// Info not available in cluster mode
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
catch (error) {
|
|
126
|
-
this.logger.error('Health check error:', error);
|
|
127
|
-
details.ping = false;
|
|
128
|
-
}
|
|
129
|
-
const latency = Date.now() - start;
|
|
130
|
-
const healthy = details.ping;
|
|
131
|
-
const status = {
|
|
132
|
-
healthy,
|
|
133
|
-
status: healthy ? 'healthy' : 'unhealthy',
|
|
134
|
-
latency,
|
|
135
|
-
timestamp: new Date(),
|
|
136
|
-
details,
|
|
137
|
-
};
|
|
138
|
-
this.lastStatus = status;
|
|
139
|
-
this.notifyCallbacks(status);
|
|
140
|
-
return status;
|
|
141
|
-
}
|
|
142
|
-
/**
|
|
143
|
-
* Returns the most recent health check result.
|
|
144
|
-
*
|
|
145
|
-
* @returns The last {@link HealthStatus}, or `null` before the first check.
|
|
146
|
-
*
|
|
147
|
-
* @example
|
|
148
|
-
* ```ts
|
|
149
|
-
* const status = health.getStatus();
|
|
150
|
-
* console.log(status?.healthy, status?.latency);
|
|
151
|
-
* ```
|
|
152
|
-
*/
|
|
153
|
-
/**
|
|
154
|
-
* Returns the most recent health check result.
|
|
155
|
-
*
|
|
156
|
-
* **Returns:**
|
|
157
|
-
* - The last {@link HealthStatus}, or `null` before the first check.
|
|
158
|
-
*
|
|
159
|
-
* **Example:**
|
|
160
|
-
* ```ts
|
|
161
|
-
* const status = health.getStatus();
|
|
162
|
-
* console.log(status?.healthy, status?.latency);
|
|
163
|
-
* ```
|
|
164
|
-
*
|
|
165
|
-
* **Parameters:**
|
|
166
|
-
* - None
|
|
167
|
-
*
|
|
168
|
-
* @returns The last result, or `null`.
|
|
169
|
-
*/
|
|
170
|
-
getStatus() {
|
|
171
|
-
return this.lastStatus;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Registers a callback for health status changes.
|
|
175
|
-
*
|
|
176
|
-
* **Behavior:**
|
|
177
|
-
* - The callback is invoked whenever a health check runs and the status changes.
|
|
178
|
-
* - Callbacks are invoked synchronously within the `check()` method.
|
|
179
|
-
* - Multiple callbacks can be registered; they are invoked in registration order.
|
|
180
|
-
*
|
|
181
|
-
* **Parameters:**
|
|
182
|
-
* - `callback` - A function receiving a {@link HealthStatus} object.
|
|
183
|
-
*
|
|
184
|
-
* @example
|
|
185
|
-
* ```ts
|
|
186
|
-
* health.onChange((status) => {
|
|
187
|
-
* console.log(`Health status: ${status.status}, latency: ${status.latency}ms`);
|
|
188
|
-
* });
|
|
189
|
-
* ```
|
|
190
|
-
*
|
|
191
|
-
* @returns `void`
|
|
192
|
-
*/
|
|
193
|
-
onChange(callback) {
|
|
194
|
-
this.callbacks.push(callback);
|
|
195
|
-
}
|
|
196
|
-
notifyCallbacks(status) {
|
|
197
|
-
for (const callback of this.callbacks) {
|
|
198
|
-
try {
|
|
199
|
-
callback(status);
|
|
200
|
-
}
|
|
201
|
-
catch (error) {
|
|
202
|
-
this.logger.error('Callback error:', error);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* Waits until the Redis connection is healthy.
|
|
208
|
-
*
|
|
209
|
-
* **Behavior:**
|
|
210
|
-
* - Polls {@link check} at 1-second intervals.
|
|
211
|
-
* - Returns `true` as soon as `status.healthy` is `true`.
|
|
212
|
-
* - Returns `false` if the timeout is reached without becoming healthy.
|
|
213
|
-
*
|
|
214
|
-
* **Parameters:**
|
|
215
|
-
* - `timeout` - Maximum time to wait in milliseconds. Default: `30000` (30 seconds).
|
|
216
|
-
*
|
|
217
|
-
* **Returns:**
|
|
218
|
-
* - `true` if the connection became healthy within the timeout.
|
|
219
|
-
* - `false` if the timeout was reached without the connection becoming healthy.
|
|
220
|
-
*
|
|
221
|
-
* **Example:**
|
|
222
|
-
* ```ts
|
|
223
|
-
* const healthy = await health.waitForHealthy(10000);
|
|
224
|
-
* // healthy === true if Redis became healthy within 10 seconds
|
|
225
|
-
* ```
|
|
226
|
-
*
|
|
227
|
-
* @returns `true` if became healthy within timeout.
|
|
228
|
-
*/
|
|
229
|
-
async waitForHealthy(timeout = 30000) {
|
|
230
|
-
const start = Date.now();
|
|
231
|
-
while (Date.now() - start < timeout) {
|
|
232
|
-
const status = await this.check();
|
|
233
|
-
if (status.healthy)
|
|
234
|
-
return true;
|
|
235
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
236
|
-
}
|
|
237
|
-
return false;
|
|
238
|
-
}
|
|
239
|
-
}
|
package/dist/lock.d.ts
DELETED
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import { RedisClientWrapper } from './client.js';
|
|
2
|
-
import { LoggerLike } from './logger.js';
|
|
3
|
-
/**
|
|
4
|
-
* Information about a distributed lock.
|
|
5
|
-
*
|
|
6
|
-
* **Fields:**
|
|
7
|
-
* - `locked`: Whether the lock is currently held.
|
|
8
|
-
* - `ttl`: Remaining TTL in seconds (when held and TTL set).
|
|
9
|
-
* - `lockId`: Unique owner id of the lock.
|
|
10
|
-
*
|
|
11
|
-
* **Example:**
|
|
12
|
-
* ```ts
|
|
13
|
-
* const info = await lock.getLockInfo('order:42');
|
|
14
|
-
* // { locked: true, ttl: 29, lockId: 'a1b2c3...' }
|
|
15
|
-
* ```
|
|
16
|
-
*/
|
|
17
|
-
export type LockInfo = {
|
|
18
|
-
/** Whether the lock is currently held. */
|
|
19
|
-
locked: boolean;
|
|
20
|
-
/** Remaining TTL in seconds (when held and TTL set). */
|
|
21
|
-
ttl?: number;
|
|
22
|
-
/** Unique owner id of the lock. */
|
|
23
|
-
lockId?: string;
|
|
24
|
-
};
|
|
25
|
-
/**
|
|
26
|
-
* Options for the distributed lock.
|
|
27
|
-
*
|
|
28
|
-
* **Fields:**
|
|
29
|
-
* - `ttl`: Lock TTL in milliseconds. Default: `30000`.
|
|
30
|
-
* - `retryCount`: Number of acquisition attempts. Default: `3`.
|
|
31
|
-
* - `retryDelay`: Base delay between retries in ms (grows exponentially). Default: `200`.
|
|
32
|
-
*
|
|
33
|
-
* **Example:**
|
|
34
|
-
* ```ts
|
|
35
|
-
* const lock = new DistributedLock(client, { ttl: 10000, retryCount: 5 });
|
|
36
|
-
* ```
|
|
37
|
-
*/
|
|
38
|
-
export interface DistributedLockOptions {
|
|
39
|
-
/** Lock TTL in milliseconds. Default: `30000`. */
|
|
40
|
-
ttl?: number;
|
|
41
|
-
/** Number of acquisition attempts. Default: `3`. */
|
|
42
|
-
retryCount?: number;
|
|
43
|
-
/** Base delay between retries in ms (grows exponentially). Default: `200`. */
|
|
44
|
-
retryDelay?: number;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Distributed mutual-exclusion lock backed by Redis.
|
|
48
|
-
*
|
|
49
|
-
* Works in standalone, sentinel and cluster modes. Acquisition uses atomic
|
|
50
|
-
* `SET ... PX NX`; release and extension use Lua scripts so only the lock owner
|
|
51
|
-
* can release or extend. `withLock` auto-extends the lock at half TTL while the
|
|
52
|
-
* critical section runs and always releases afterwards.
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* ```ts
|
|
56
|
-
* const lock = new DistributedLock(client, { ttl: 30000, retryCount: 5 });
|
|
57
|
-
* const acquired = await lock.acquire('order:42');
|
|
58
|
-
* if (acquired) {
|
|
59
|
-
* try {
|
|
60
|
-
* // critical section
|
|
61
|
-
* } finally {
|
|
62
|
-
* await lock.release('order:42');
|
|
63
|
-
* }
|
|
64
|
-
* }
|
|
65
|
-
* ```
|
|
66
|
-
*/
|
|
67
|
-
export declare class DistributedLock {
|
|
68
|
-
private client;
|
|
69
|
-
private logger;
|
|
70
|
-
private defaultTTL;
|
|
71
|
-
private defaultRetryCount;
|
|
72
|
-
private defaultRetryDelay;
|
|
73
|
-
/**
|
|
74
|
-
* Creates a distributed lock bound to a Redis client.
|
|
75
|
-
*
|
|
76
|
-
* @param client - The underlying {@link RedisClientWrapper}.
|
|
77
|
-
* @param logger - Optional pino-compatible logger; defaults to `console`.
|
|
78
|
-
* @param options - Defaults for `ttl` (ms), `retryCount` and `retryDelay`.
|
|
79
|
-
*
|
|
80
|
-
* @example
|
|
81
|
-
* ```ts
|
|
82
|
-
* const lock = new DistributedLock(client, { ttl: 10000, retryCount: 3 });
|
|
83
|
-
* ```
|
|
84
|
-
*/
|
|
85
|
-
constructor(client: RedisClientWrapper, logger?: LoggerLike, options?: Partial<DistributedLockOptions>);
|
|
86
|
-
private getLockKey;
|
|
87
|
-
private generateLockId;
|
|
88
|
-
private executeWithRetry;
|
|
89
|
-
/**
|
|
90
|
-
* Attempts to acquire the lock for a key.
|
|
91
|
-
*
|
|
92
|
-
* Uses atomic `SET lock:<key> <id> PX <ttl> NX` with exponential backoff
|
|
93
|
-
* retries. Locks expire automatically after `ttl` ms, so a crashed holder
|
|
94
|
-
* never blocks others forever.
|
|
95
|
-
*
|
|
96
|
-
* @param key - The resource to lock, e.g. `'order:42'` (stored as `lock:order:42`).
|
|
97
|
-
* @param ttl - Lock TTL in milliseconds (default: `30000`).
|
|
98
|
-
*
|
|
99
|
-
* @returns `true` when the lock was acquired.
|
|
100
|
-
*
|
|
101
|
-
* @example
|
|
102
|
-
* ```ts
|
|
103
|
-
* const acquired = await lock.acquire('order:42', 10000);
|
|
104
|
-
* // acquired === true when lock was successfully acquired
|
|
105
|
-
* ```
|
|
106
|
-
*/
|
|
107
|
-
acquire(key: string, ttl?: number): Promise<boolean>;
|
|
108
|
-
/**
|
|
109
|
-
* Releases the lock, but only if this process still owns it.
|
|
110
|
-
*
|
|
111
|
-
* Uses an atomic Lua check-and-delete so a lock whose TTL expired (and was
|
|
112
|
-
* re-acquired by someone else) is never removed by the old owner.
|
|
113
|
-
*
|
|
114
|
-
* @param key - The locked resource.
|
|
115
|
-
*
|
|
116
|
-
* @returns `true` if the lock was released, `false` if not owned or missing.
|
|
117
|
-
*
|
|
118
|
-
* @example
|
|
119
|
-
* ```ts
|
|
120
|
-
* await lock.release('order:42');
|
|
121
|
-
* ```
|
|
122
|
-
*/
|
|
123
|
-
release(key: string): Promise<boolean>;
|
|
124
|
-
/**
|
|
125
|
-
* Force-releases a lock without checking ownership.
|
|
126
|
-
*
|
|
127
|
-
* Use with care: only for emergency cleanup or when the holder is known to
|
|
128
|
-
* be gone. This is what `withLock` falls back to when a normal release fails.
|
|
129
|
-
*
|
|
130
|
-
* @param key - The locked resource.
|
|
131
|
-
*
|
|
132
|
-
* @returns `true` if a lock existed and was deleted.
|
|
133
|
-
*
|
|
134
|
-
* @example
|
|
135
|
-
* ```ts
|
|
136
|
-
* await lock.releaseForce('order:42');
|
|
137
|
-
* ```
|
|
138
|
-
*/
|
|
139
|
-
releaseForce(key: string): Promise<boolean>;
|
|
140
|
-
/**
|
|
141
|
-
* Extends the TTL of a lock this process still owns.
|
|
142
|
-
*
|
|
143
|
-
* Uses an atomic Lua script so a re-acquired lock is never extended by the
|
|
144
|
-
* old owner.
|
|
145
|
-
*
|
|
146
|
-
* @param key - The locked resource.
|
|
147
|
-
* @param ttl - New TTL in milliseconds (default: `30000`).
|
|
148
|
-
*
|
|
149
|
-
* @returns `true` if the lock was extended.
|
|
150
|
-
*
|
|
151
|
-
* @example
|
|
152
|
-
* ```ts
|
|
153
|
-
* const extended = await lock.extend('order:42', 30000);
|
|
154
|
-
* // extended === true when lock TTL was renewed
|
|
155
|
-
* ```
|
|
156
|
-
*/
|
|
157
|
-
extend(key: string, ttl?: number): Promise<boolean>;
|
|
158
|
-
/**
|
|
159
|
-
* Runs a critical section while holding a lock.
|
|
160
|
-
*
|
|
161
|
-
* Acquires the lock (with retries), auto-extends it at half TTL while `fn`
|
|
162
|
-
* runs, detects a lost lock, and always releases afterwards (force-releasing
|
|
163
|
-
* if a normal release fails).
|
|
164
|
-
*
|
|
165
|
-
* @param key - The resource to lock.
|
|
166
|
-
* @param fn - The critical section to run exclusively.
|
|
167
|
-
* @param options - Per-call `ttl` (ms), `retryCount`, `retryDelay`.
|
|
168
|
-
*
|
|
169
|
-
* @returns The return value of `fn`.
|
|
170
|
-
*
|
|
171
|
-
* @throws {@link RedisError} with code `LOCK_ACQUISITION_FAILED` when the lock
|
|
172
|
-
* cannot be acquired, or `LOCK_LOST` when the lock expired mid-execution.
|
|
173
|
-
*
|
|
174
|
-
* @example
|
|
175
|
-
* ```ts
|
|
176
|
-
* const result = await lock.withLock('inventory:sku-1', async () => {
|
|
177
|
-
* return await updateStock();
|
|
178
|
-
* });
|
|
179
|
-
* ```
|
|
180
|
-
*/
|
|
181
|
-
withLock<T>(key: string, fn: () => Promise<T>, options?: DistributedLockOptions): Promise<T>;
|
|
182
|
-
/**
|
|
183
|
-
* Checks whether a lock is currently held.
|
|
184
|
-
*
|
|
185
|
-
* @param key - The locked resource.
|
|
186
|
-
*
|
|
187
|
-
* @returns `true` if the lock exists (held by anyone).
|
|
188
|
-
*
|
|
189
|
-
* @example
|
|
190
|
-
* ```ts
|
|
191
|
-
* const busy = await lock.isLocked('order:42');
|
|
192
|
-
* ```
|
|
193
|
-
*/
|
|
194
|
-
isLocked(key: string): Promise<boolean>;
|
|
195
|
-
/**
|
|
196
|
-
* Returns details about a lock.
|
|
197
|
-
*
|
|
198
|
-
* @param key - The locked resource.
|
|
199
|
-
*
|
|
200
|
-
* @returns `{ locked: false }` when not held, otherwise `{ locked: true, ttl, lockId }`.
|
|
201
|
-
*
|
|
202
|
-
* @example
|
|
203
|
-
* ```ts
|
|
204
|
-
* const info = await lock.getLockInfo('order:42');
|
|
205
|
-
* // { locked: true, ttl: 29, lockId: 'a1b2c3...' }
|
|
206
|
-
* ```
|
|
207
|
-
*/
|
|
208
|
-
getLockInfo(key: string): Promise<LockInfo>;
|
|
209
|
-
/**
|
|
210
|
-
* Returns the owner id of a lock.
|
|
211
|
-
*
|
|
212
|
-
* @param key - The locked resource.
|
|
213
|
-
*
|
|
214
|
-
* @returns The lock id (random hex token), or `null` when not held.
|
|
215
|
-
*
|
|
216
|
-
* @example
|
|
217
|
-
* ```ts
|
|
218
|
-
* const owner = await lock.getLockOwner('order:42');
|
|
219
|
-
* ```
|
|
220
|
-
*/
|
|
221
|
-
getLockOwner(key: string): Promise<string | null>;
|
|
222
|
-
/**
|
|
223
|
-
* Returns the remaining TTL of a lock in seconds.
|
|
224
|
-
*
|
|
225
|
-
* @param key - The locked resource.
|
|
226
|
-
*
|
|
227
|
-
* @returns Remaining seconds (`0` when not held or expired).
|
|
228
|
-
*
|
|
229
|
-
* @example
|
|
230
|
-
* ```ts
|
|
231
|
-
* const remaining = await lock.getLockTTL('order:42');
|
|
232
|
-
* ```
|
|
233
|
-
*/
|
|
234
|
-
getLockTTL(key: string): Promise<number>;
|
|
235
|
-
/**
|
|
236
|
-
* Deletes every lock key (`lock:*`) from Redis.
|
|
237
|
-
*
|
|
238
|
-
* Intended for tests and emergency recovery only.
|
|
239
|
-
*
|
|
240
|
-
* @returns The number of deleted locks.
|
|
241
|
-
*
|
|
242
|
-
* @example
|
|
243
|
-
* ```ts
|
|
244
|
-
* const removed = await lock.cleanupAll();
|
|
245
|
-
* ```
|
|
246
|
-
*/
|
|
247
|
-
cleanupAll(): Promise<number>;
|
|
248
|
-
}
|