cachette 4.0.26-remove-redlock.0 → 4.0.26
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.
|
@@ -19,12 +19,15 @@ export declare class RedisCache extends CacheInstance {
|
|
|
19
19
|
static ERROR_PREFIX: string;
|
|
20
20
|
static NUMBER_PREFIX: string;
|
|
21
21
|
static REDIS_CONNECTION_TIMEOUT_MS: number;
|
|
22
|
-
static
|
|
23
|
-
static
|
|
24
|
-
static
|
|
22
|
+
static REDLOCK_RETRY_COUNT: number;
|
|
23
|
+
static REDLOCK_RETRY_DELAY_MS: number;
|
|
24
|
+
static REDLOCK_CLOCK_DRIFT_FACTOR: number;
|
|
25
|
+
static REDLOCK_JITTER_MS: number;
|
|
25
26
|
private redisClient;
|
|
26
27
|
private ready;
|
|
27
28
|
private url;
|
|
29
|
+
private redlock;
|
|
30
|
+
private redlockWithoutRetry;
|
|
28
31
|
constructor(redisUrl: string, readOnly?: boolean);
|
|
29
32
|
/**
|
|
30
33
|
* @inheritdoc
|
|
@@ -40,6 +43,7 @@ export declare class RedisCache extends CacheInstance {
|
|
|
40
43
|
* with an UncaughtException.
|
|
41
44
|
*/
|
|
42
45
|
errorStrategy(): void;
|
|
46
|
+
redlockErrorStrategy(err: any): void;
|
|
43
47
|
/**
|
|
44
48
|
* The end event is emitted by the redis client when an
|
|
45
49
|
* established connection has ended.
|
|
@@ -107,6 +111,8 @@ export declare class RedisCache extends CacheInstance {
|
|
|
107
111
|
clearMemory(): Promise<void>;
|
|
108
112
|
/**
|
|
109
113
|
* @inheritdoc
|
|
114
|
+
* Locking through the redlock algorithm
|
|
115
|
+
* https://redis.io/topics/distlock
|
|
110
116
|
*/
|
|
111
117
|
isLockingSupported(): boolean;
|
|
112
118
|
/**
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.RedisCache = exports.SIZE_THRESHOLD_WARNING_BYTES = void 0;
|
|
4
4
|
const ioredis_1 = require("ioredis");
|
|
5
|
-
const
|
|
5
|
+
const Redlock = require("redlock");
|
|
6
6
|
const CacheInstance_1 = require("./CacheInstance");
|
|
7
7
|
exports.SIZE_THRESHOLD_WARNING_BYTES = 20_000_000;
|
|
8
8
|
/**
|
|
@@ -25,12 +25,20 @@ class RedisCache extends CacheInstance_1.CacheInstance {
|
|
|
25
25
|
static NUMBER_PREFIX = 'f405eed4-507c-4aa5-a6d2-c1813d584b8f-NUMBER';
|
|
26
26
|
static REDIS_CONNECTION_TIMEOUT_MS = parseInt(process.env.REDIS_CONNECTION_TIMEOUT_MS, 10) || 5000;
|
|
27
27
|
// Backward compatible: REDLOCK_* takes precedence, then CACHETTE_LOCK_*
|
|
28
|
-
static
|
|
29
|
-
static
|
|
30
|
-
static
|
|
28
|
+
static REDLOCK_RETRY_COUNT = parseInt(process.env.REDLOCK_RETRY_COUNT, 10) || RedisCache.LOCK_RETRY_COUNT; // lib. default: 20
|
|
29
|
+
static REDLOCK_RETRY_DELAY_MS = parseInt(process.env.REDLOCK_RETRY_DELAY_MS, 10) || RedisCache.LOCK_RETRY_DELAY_MS; // lib. default: 200
|
|
30
|
+
static REDLOCK_CLOCK_DRIFT_FACTOR = parseInt(process.env.REDLOCK_CLOCK_DRIFT_FACTOR, 10) || 0.01; // lib. default: 0.01
|
|
31
|
+
static REDLOCK_JITTER_MS = parseInt(process.env.REDLOCK_JITTER_MS, 10) || 200; // lib. default: 200
|
|
31
32
|
redisClient;
|
|
32
33
|
ready = false;
|
|
33
34
|
url;
|
|
35
|
+
// We manage several redlock instances because some options (like retryCount)
|
|
36
|
+
// are set at redlock init. By having these options in our constructor too
|
|
37
|
+
// (and only having one redlock with fixed behavior), we would be unable to
|
|
38
|
+
// support mixing calls requiring one behavior, then another.
|
|
39
|
+
// And so, we have as many redlocks as we need to honor these runtime needs.
|
|
40
|
+
redlock;
|
|
41
|
+
redlockWithoutRetry;
|
|
34
42
|
constructor(redisUrl, readOnly = false) {
|
|
35
43
|
super();
|
|
36
44
|
if (!redisUrl || (!redisUrl.startsWith('redis://') && !redisUrl.startsWith('rediss://'))) {
|
|
@@ -48,9 +56,26 @@ class RedisCache extends CacheInstance_1.CacheInstance {
|
|
|
48
56
|
// This prevents get/setValue calls from hanging if there is no active connection
|
|
49
57
|
enableOfflineQueue: false,
|
|
50
58
|
});
|
|
59
|
+
this.redlock = new Redlock([this.redisClient], {
|
|
60
|
+
// Hack until Redlock 5.x is out of beta
|
|
61
|
+
driftFactor: RedisCache.REDLOCK_CLOCK_DRIFT_FACTOR,
|
|
62
|
+
retryCount: RedisCache.REDLOCK_RETRY_COUNT,
|
|
63
|
+
retryDelay: RedisCache.REDLOCK_RETRY_DELAY_MS,
|
|
64
|
+
retryJitter: RedisCache.REDLOCK_JITTER_MS,
|
|
65
|
+
});
|
|
66
|
+
this.redlockWithoutRetry = new Redlock([this.redisClient], {
|
|
67
|
+
// Hack until Redlock 5.x is out of beta
|
|
68
|
+
driftFactor: RedisCache.REDLOCK_CLOCK_DRIFT_FACTOR,
|
|
69
|
+
retryCount: 0,
|
|
70
|
+
retryDelay: 0,
|
|
71
|
+
retryJitter: 0,
|
|
72
|
+
});
|
|
51
73
|
this.redisClient.on('ready', this.startConnectionStrategy.bind(this));
|
|
52
74
|
this.redisClient.on('end', this.endConnectionStrategy.bind(this));
|
|
53
75
|
this.redisClient.on('error', this.errorStrategy.bind(this));
|
|
76
|
+
// TODO when migrating to Redlock v5: rename 'clientError' to 'error'
|
|
77
|
+
this.redlock.on('clientError', this.redlockErrorStrategy.bind(this));
|
|
78
|
+
this.redlockWithoutRetry.on('clientError', this.redlockErrorStrategy.bind(this));
|
|
54
79
|
}
|
|
55
80
|
/**
|
|
56
81
|
* @inheritdoc
|
|
@@ -75,6 +100,9 @@ class RedisCache extends CacheInstance_1.CacheInstance {
|
|
|
75
100
|
errorStrategy() {
|
|
76
101
|
this.emit('warn', 'Error while connected to the Redis cache!');
|
|
77
102
|
}
|
|
103
|
+
redlockErrorStrategy(err) {
|
|
104
|
+
this.emit('warn', 'Redlock error:', err);
|
|
105
|
+
}
|
|
78
106
|
/**
|
|
79
107
|
* The end event is emitted by the redis client when an
|
|
80
108
|
* established connection has ended.
|
|
@@ -297,6 +325,8 @@ class RedisCache extends CacheInstance_1.CacheInstance {
|
|
|
297
325
|
}
|
|
298
326
|
/**
|
|
299
327
|
* @inheritdoc
|
|
328
|
+
* Locking through the redlock algorithm
|
|
329
|
+
* https://redis.io/topics/distlock
|
|
300
330
|
*/
|
|
301
331
|
isLockingSupported() {
|
|
302
332
|
return true;
|
|
@@ -305,23 +335,20 @@ class RedisCache extends CacheInstance_1.CacheInstance {
|
|
|
305
335
|
* @inheritdoc
|
|
306
336
|
*/
|
|
307
337
|
async lock(resource, ttlMs, retry = true) {
|
|
308
|
-
const
|
|
309
|
-
const
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
throw new Error(`Failed to acquire lock on ${resource} after ${maxAttempts} attempts`);
|
|
338
|
+
const redlock = retry === false ? this.redlockWithoutRetry : this.redlock;
|
|
339
|
+
const internalLock = await redlock.lock(resource, ttlMs);
|
|
340
|
+
return {
|
|
341
|
+
value: internalLock.value,
|
|
342
|
+
unlock: async () => {
|
|
343
|
+
try {
|
|
344
|
+
await internalLock.unlock();
|
|
345
|
+
}
|
|
346
|
+
catch (err) {
|
|
347
|
+
if (internalLock.expiration > Date.now())
|
|
348
|
+
throw err;
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
};
|
|
325
352
|
}
|
|
326
353
|
/**
|
|
327
354
|
* @inheritdoc
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RedisCache.js","sourceRoot":"","sources":["../../../src/lib/RedisCache.ts"],"names":[],"mappings":";;;AAAA,qCAA4B;AAC5B,
|
|
1
|
+
{"version":3,"file":"RedisCache.js","sourceRoot":"","sources":["../../../src/lib/RedisCache.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cachette",
|
|
3
|
-
"version": "4.0.26
|
|
3
|
+
"version": "4.0.26",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=20",
|
|
6
6
|
"npm": ">=10"
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"@types/eslint__js": "8.x",
|
|
60
60
|
"@types/mocha": "10.x",
|
|
61
61
|
"@types/node": "20.x",
|
|
62
|
+
"@types/redlock": "4.x",
|
|
62
63
|
"@types/sinon": "21.x",
|
|
63
64
|
"chai": "6.x",
|
|
64
65
|
"eslint": "10.x",
|
|
@@ -73,6 +74,7 @@
|
|
|
73
74
|
},
|
|
74
75
|
"dependencies": {
|
|
75
76
|
"ioredis": "5.x",
|
|
76
|
-
"lru-cache": "11.x"
|
|
77
|
+
"lru-cache": "11.x",
|
|
78
|
+
"redlock": "4.x"
|
|
77
79
|
}
|
|
78
80
|
}
|
package/src/lib/RedisCache.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Redis from 'ioredis';
|
|
2
|
-
import
|
|
2
|
+
import * as Redlock from 'redlock';
|
|
3
3
|
|
|
4
4
|
import { CachableValue, CacheInstance, Lock } from './CacheInstance';
|
|
5
5
|
|
|
@@ -26,15 +26,23 @@ export class RedisCache extends CacheInstance {
|
|
|
26
26
|
|
|
27
27
|
public static REDIS_CONNECTION_TIMEOUT_MS = parseInt(process.env.REDIS_CONNECTION_TIMEOUT_MS as string, 10) || 5000;
|
|
28
28
|
// Backward compatible: REDLOCK_* takes precedence, then CACHETTE_LOCK_*
|
|
29
|
-
public static
|
|
30
|
-
parseInt(process.env.REDLOCK_RETRY_COUNT as string, 10) || RedisCache.LOCK_RETRY_COUNT;
|
|
31
|
-
public static
|
|
32
|
-
parseInt(process.env.REDLOCK_RETRY_DELAY_MS as string, 10) || RedisCache.LOCK_RETRY_DELAY_MS;
|
|
33
|
-
public static
|
|
29
|
+
public static REDLOCK_RETRY_COUNT =
|
|
30
|
+
parseInt(process.env.REDLOCK_RETRY_COUNT as string, 10) || RedisCache.LOCK_RETRY_COUNT; // lib. default: 20
|
|
31
|
+
public static REDLOCK_RETRY_DELAY_MS =
|
|
32
|
+
parseInt(process.env.REDLOCK_RETRY_DELAY_MS as string, 10) || RedisCache.LOCK_RETRY_DELAY_MS; // lib. default: 200
|
|
33
|
+
public static REDLOCK_CLOCK_DRIFT_FACTOR = parseInt(process.env.REDLOCK_CLOCK_DRIFT_FACTOR as string, 10) || 0.01; // lib. default: 0.01
|
|
34
|
+
public static REDLOCK_JITTER_MS = parseInt(process.env.REDLOCK_JITTER_MS as string, 10) || 200; // lib. default: 200
|
|
34
35
|
|
|
35
36
|
private redisClient: Redis;
|
|
36
37
|
private ready = false;
|
|
37
38
|
private url: string;
|
|
39
|
+
// We manage several redlock instances because some options (like retryCount)
|
|
40
|
+
// are set at redlock init. By having these options in our constructor too
|
|
41
|
+
// (and only having one redlock with fixed behavior), we would be unable to
|
|
42
|
+
// support mixing calls requiring one behavior, then another.
|
|
43
|
+
// And so, we have as many redlocks as we need to honor these runtime needs.
|
|
44
|
+
private redlock: Redlock;
|
|
45
|
+
private redlockWithoutRetry: Redlock;
|
|
38
46
|
|
|
39
47
|
constructor(redisUrl: string, readOnly = false) {
|
|
40
48
|
super();
|
|
@@ -55,10 +63,28 @@ export class RedisCache extends CacheInstance {
|
|
|
55
63
|
// This prevents get/setValue calls from hanging if there is no active connection
|
|
56
64
|
enableOfflineQueue: false,
|
|
57
65
|
});
|
|
66
|
+
this.redlock = new Redlock([this.redisClient as unknown as Redlock.CompatibleRedisClient], {
|
|
67
|
+
// Hack until Redlock 5.x is out of beta
|
|
68
|
+
driftFactor: RedisCache.REDLOCK_CLOCK_DRIFT_FACTOR,
|
|
69
|
+
retryCount: RedisCache.REDLOCK_RETRY_COUNT,
|
|
70
|
+
retryDelay: RedisCache.REDLOCK_RETRY_DELAY_MS,
|
|
71
|
+
retryJitter: RedisCache.REDLOCK_JITTER_MS,
|
|
72
|
+
});
|
|
73
|
+
this.redlockWithoutRetry = new Redlock([this.redisClient as unknown as Redlock.CompatibleRedisClient], {
|
|
74
|
+
// Hack until Redlock 5.x is out of beta
|
|
75
|
+
driftFactor: RedisCache.REDLOCK_CLOCK_DRIFT_FACTOR,
|
|
76
|
+
retryCount: 0,
|
|
77
|
+
retryDelay: 0,
|
|
78
|
+
retryJitter: 0,
|
|
79
|
+
});
|
|
58
80
|
|
|
59
81
|
this.redisClient.on('ready', this.startConnectionStrategy.bind(this));
|
|
60
82
|
this.redisClient.on('end', this.endConnectionStrategy.bind(this));
|
|
61
83
|
this.redisClient.on('error', this.errorStrategy.bind(this));
|
|
84
|
+
|
|
85
|
+
// TODO when migrating to Redlock v5: rename 'clientError' to 'error'
|
|
86
|
+
this.redlock.on('clientError', this.redlockErrorStrategy.bind(this));
|
|
87
|
+
this.redlockWithoutRetry.on('clientError', this.redlockErrorStrategy.bind(this));
|
|
62
88
|
}
|
|
63
89
|
|
|
64
90
|
/**
|
|
@@ -87,6 +113,10 @@ export class RedisCache extends CacheInstance {
|
|
|
87
113
|
this.emit('warn', 'Error while connected to the Redis cache!');
|
|
88
114
|
}
|
|
89
115
|
|
|
116
|
+
public redlockErrorStrategy(err: any): void {
|
|
117
|
+
this.emit('warn', 'Redlock error:', err);
|
|
118
|
+
}
|
|
119
|
+
|
|
90
120
|
/**
|
|
91
121
|
* The end event is emitted by the redis client when an
|
|
92
122
|
* established connection has ended.
|
|
@@ -338,6 +368,8 @@ export class RedisCache extends CacheInstance {
|
|
|
338
368
|
|
|
339
369
|
/**
|
|
340
370
|
* @inheritdoc
|
|
371
|
+
* Locking through the redlock algorithm
|
|
372
|
+
* https://redis.io/topics/distlock
|
|
341
373
|
*/
|
|
342
374
|
public isLockingSupported(): boolean {
|
|
343
375
|
return true;
|
|
@@ -347,33 +379,19 @@ export class RedisCache extends CacheInstance {
|
|
|
347
379
|
* @inheritdoc
|
|
348
380
|
*/
|
|
349
381
|
public async lock(resource: string, ttlMs: number, retry = true): Promise<Lock> {
|
|
350
|
-
const
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
value,
|
|
364
|
-
);
|
|
365
|
-
},
|
|
366
|
-
};
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
if (attempt < maxAttempts - 1) {
|
|
370
|
-
await new Promise((resolve) =>
|
|
371
|
-
setTimeout(resolve, RedisCache.LOCK_RETRY_DELAY + Math.random() * RedisCache.LOCK_JITTER_MS),
|
|
372
|
-
);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
throw new Error(`Failed to acquire lock on ${resource} after ${maxAttempts} attempts`);
|
|
382
|
+
const redlock = retry === false ? this.redlockWithoutRetry : this.redlock;
|
|
383
|
+
const internalLock = await redlock.lock(resource, ttlMs);
|
|
384
|
+
|
|
385
|
+
return {
|
|
386
|
+
value: internalLock.value,
|
|
387
|
+
unlock: async () => {
|
|
388
|
+
try {
|
|
389
|
+
await internalLock.unlock();
|
|
390
|
+
} catch (err) {
|
|
391
|
+
if (internalLock.expiration > Date.now()) throw err;
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
};
|
|
377
395
|
}
|
|
378
396
|
|
|
379
397
|
/**
|
package/test/CacheClient_test.ts
CHANGED
|
@@ -328,4 +328,16 @@ describe('CacheClient', () => {
|
|
|
328
328
|
expect(() => cacheClient['buildCacheKey']('functionName', [obj2])).to.throw();
|
|
329
329
|
});
|
|
330
330
|
});
|
|
331
|
+
|
|
332
|
+
describe('Redlock maintenance reminder', () => {
|
|
333
|
+
it('is still on Redlock v4, or was carefully migrated to v5', () => {
|
|
334
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
335
|
+
const redlockVersion = require('../../package.json').dependencies.redlock;
|
|
336
|
+
if (redlockVersion !== '4.x') {
|
|
337
|
+
throw new Error(
|
|
338
|
+
'Migrating Redlock to v5? This breaking test is a reminder to:\n 1. Migrate v4 handling of `clientError` events into v5 `error` events\n 2. Review error handling: Redlock v5 throws at many places, while Redlock v4 only threw in its constructor\n 3. Review other breaking changes provided by the upgrade guide, if Redlock maintainers provide one when shipping v5',
|
|
339
|
+
);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
});
|
|
331
343
|
});
|