cachette 4.0.24 → 4.0.26-remove-redlock.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/dist/src/lib/CacheInstance.js.map +1 -1
- package/dist/src/lib/RedisCache.d.ts +3 -9
- package/dist/src/lib/RedisCache.js +21 -40
- package/dist/src/lib/RedisCache.js.map +1 -1
- package/package.json +2 -4
- package/src/lib/CacheInstance.ts +7 -2
- package/src/lib/RedisCache.ts +32 -44
- package/test/CacheClient_test.ts +0 -12
- package/test/CacheInstance_test.ts +10 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CacheInstance.js","sourceRoot":"","sources":["../../../src/lib/CacheInstance.ts"],"names":[],"mappings":";;;AAAA,6CAA2C;AAc3C,MAAsB,aAAc,SAAQ,0BAAY;IACtD,kDAAkD;IAC3C,MAAM,CAAC,gBAAgB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAmC,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;IAC9F,MAAM,CAAC,mBAAmB,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,4BAAsC,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC;IAyE5G;;OAEG;IACI,kBAAkB;QACvB,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;;OAQG;IACI,IAAI,CAAC,QAAgB,EAAE,KAAa,EAAE,KAAe;QAC1D,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,MAAM,CAAC,IAAU;QAC5B,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;IACtB,CAAC;IAED;;OAEG;IACI,OAAO,CAAC,MAAc;QAC3B,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC;IACjC,CAAC;IAED;;OAEG;IACI,IAAI;QACT,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;YAC7B,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACK,aAAa,GAA8C,EAAE,CAAC;IAE9D,KAAK,CAAC,yBAAyB,
|
|
1
|
+
{"version":3,"file":"CacheInstance.js","sourceRoot":"","sources":["../../../src/lib/CacheInstance.ts"],"names":[],"mappings":"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"}
|
|
@@ -19,15 +19,12 @@ 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
|
|
25
|
-
static REDLOCK_JITTER_MS: number;
|
|
22
|
+
static LOCK_MAX_ATTEMPTS: number;
|
|
23
|
+
static LOCK_RETRY_DELAY: number;
|
|
24
|
+
static LOCK_JITTER_MS: number;
|
|
26
25
|
private redisClient;
|
|
27
26
|
private ready;
|
|
28
27
|
private url;
|
|
29
|
-
private redlock;
|
|
30
|
-
private redlockWithoutRetry;
|
|
31
28
|
constructor(redisUrl: string, readOnly?: boolean);
|
|
32
29
|
/**
|
|
33
30
|
* @inheritdoc
|
|
@@ -43,7 +40,6 @@ export declare class RedisCache extends CacheInstance {
|
|
|
43
40
|
* with an UncaughtException.
|
|
44
41
|
*/
|
|
45
42
|
errorStrategy(): void;
|
|
46
|
-
redlockErrorStrategy(err: any): void;
|
|
47
43
|
/**
|
|
48
44
|
* The end event is emitted by the redis client when an
|
|
49
45
|
* established connection has ended.
|
|
@@ -111,8 +107,6 @@ export declare class RedisCache extends CacheInstance {
|
|
|
111
107
|
clearMemory(): Promise<void>;
|
|
112
108
|
/**
|
|
113
109
|
* @inheritdoc
|
|
114
|
-
* Locking through the redlock algorithm
|
|
115
|
-
* https://redis.io/topics/distlock
|
|
116
110
|
*/
|
|
117
111
|
isLockingSupported(): boolean;
|
|
118
112
|
/**
|
|
@@ -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 node_crypto_1 = require("node:crypto");
|
|
6
6
|
const CacheInstance_1 = require("./CacheInstance");
|
|
7
7
|
exports.SIZE_THRESHOLD_WARNING_BYTES = 20_000_000;
|
|
8
8
|
/**
|
|
@@ -25,20 +25,12 @@ 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
|
|
31
|
-
static REDLOCK_JITTER_MS = parseInt(process.env.REDLOCK_JITTER_MS, 10) || 200; // lib. default: 200
|
|
28
|
+
static LOCK_MAX_ATTEMPTS = parseInt(process.env.REDLOCK_RETRY_COUNT, 10) || RedisCache.LOCK_RETRY_COUNT;
|
|
29
|
+
static LOCK_RETRY_DELAY = parseInt(process.env.REDLOCK_RETRY_DELAY_MS, 10) || RedisCache.LOCK_RETRY_DELAY_MS;
|
|
30
|
+
static LOCK_JITTER_MS = parseInt(process.env.REDLOCK_JITTER_MS, 10) || 200;
|
|
32
31
|
redisClient;
|
|
33
32
|
ready = false;
|
|
34
33
|
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;
|
|
42
34
|
constructor(redisUrl, readOnly = false) {
|
|
43
35
|
super();
|
|
44
36
|
if (!redisUrl || (!redisUrl.startsWith('redis://') && !redisUrl.startsWith('rediss://'))) {
|
|
@@ -56,26 +48,9 @@ class RedisCache extends CacheInstance_1.CacheInstance {
|
|
|
56
48
|
// This prevents get/setValue calls from hanging if there is no active connection
|
|
57
49
|
enableOfflineQueue: false,
|
|
58
50
|
});
|
|
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
|
-
});
|
|
73
51
|
this.redisClient.on('ready', this.startConnectionStrategy.bind(this));
|
|
74
52
|
this.redisClient.on('end', this.endConnectionStrategy.bind(this));
|
|
75
53
|
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));
|
|
79
54
|
}
|
|
80
55
|
/**
|
|
81
56
|
* @inheritdoc
|
|
@@ -100,9 +75,6 @@ class RedisCache extends CacheInstance_1.CacheInstance {
|
|
|
100
75
|
errorStrategy() {
|
|
101
76
|
this.emit('warn', 'Error while connected to the Redis cache!');
|
|
102
77
|
}
|
|
103
|
-
redlockErrorStrategy(err) {
|
|
104
|
-
this.emit('warn', 'Redlock error:', err);
|
|
105
|
-
}
|
|
106
78
|
/**
|
|
107
79
|
* The end event is emitted by the redis client when an
|
|
108
80
|
* established connection has ended.
|
|
@@ -325,8 +297,6 @@ class RedisCache extends CacheInstance_1.CacheInstance {
|
|
|
325
297
|
}
|
|
326
298
|
/**
|
|
327
299
|
* @inheritdoc
|
|
328
|
-
* Locking through the redlock algorithm
|
|
329
|
-
* https://redis.io/topics/distlock
|
|
330
300
|
*/
|
|
331
301
|
isLockingSupported() {
|
|
332
302
|
return true;
|
|
@@ -335,12 +305,23 @@ class RedisCache extends CacheInstance_1.CacheInstance {
|
|
|
335
305
|
* @inheritdoc
|
|
336
306
|
*/
|
|
337
307
|
async lock(resource, ttlMs, retry = true) {
|
|
338
|
-
const
|
|
339
|
-
const
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
308
|
+
const maxAttempts = retry === false ? 1 : RedisCache.LOCK_MAX_ATTEMPTS;
|
|
309
|
+
const value = (0, node_crypto_1.randomUUID)();
|
|
310
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
311
|
+
const result = await this.redisClient.set(resource, value, 'PX', ttlMs, 'NX');
|
|
312
|
+
if (result === 'OK') {
|
|
313
|
+
return {
|
|
314
|
+
value,
|
|
315
|
+
unlock: async () => {
|
|
316
|
+
await this.redisClient.eval('if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end', 1, resource, value);
|
|
317
|
+
},
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
if (attempt < maxAttempts - 1) {
|
|
321
|
+
await new Promise((resolve) => setTimeout(resolve, RedisCache.LOCK_RETRY_DELAY + Math.random() * RedisCache.LOCK_JITTER_MS));
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
throw new Error(`Failed to acquire lock on ${resource} after ${maxAttempts} attempts`);
|
|
344
325
|
}
|
|
345
326
|
/**
|
|
346
327
|
* @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.
|
|
3
|
+
"version": "4.0.26-remove-redlock.0",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=20",
|
|
6
6
|
"npm": ">=10"
|
|
@@ -59,7 +59,6 @@
|
|
|
59
59
|
"@types/eslint__js": "8.x",
|
|
60
60
|
"@types/mocha": "10.x",
|
|
61
61
|
"@types/node": "20.x",
|
|
62
|
-
"@types/redlock": "4.x",
|
|
63
62
|
"@types/sinon": "21.x",
|
|
64
63
|
"chai": "6.x",
|
|
65
64
|
"eslint": "10.x",
|
|
@@ -74,7 +73,6 @@
|
|
|
74
73
|
},
|
|
75
74
|
"dependencies": {
|
|
76
75
|
"ioredis": "5.x",
|
|
77
|
-
"lru-cache": "11.x"
|
|
78
|
-
"redlock": "4.x"
|
|
76
|
+
"lru-cache": "11.x"
|
|
79
77
|
}
|
|
80
78
|
}
|
package/src/lib/CacheInstance.ts
CHANGED
|
@@ -139,7 +139,10 @@ export abstract class CacheInstance extends EventEmitter {
|
|
|
139
139
|
*/
|
|
140
140
|
private activeFetches: { [key: string]: Promise<CachableValue> } = {};
|
|
141
141
|
|
|
142
|
-
private async getValueWithErrorHandling(
|
|
142
|
+
private async getValueWithErrorHandling(
|
|
143
|
+
key: string,
|
|
144
|
+
shouldCacheError?: (err: Error) => boolean,
|
|
145
|
+
): Promise<CachableValue> {
|
|
143
146
|
const cached = await this.getValue(key);
|
|
144
147
|
if (cached instanceof Error) {
|
|
145
148
|
if (shouldCacheError && shouldCacheError(cached)) {
|
|
@@ -207,7 +210,9 @@ export abstract class CacheInstance extends EventEmitter {
|
|
|
207
210
|
}
|
|
208
211
|
|
|
209
212
|
if (lockErrorMessage) {
|
|
210
|
-
throw new Error(
|
|
213
|
+
throw new Error(
|
|
214
|
+
`Failed to acquire lock for key ${key}. No active fetch or cached value found: ${lockErrorMessage}`,
|
|
215
|
+
);
|
|
211
216
|
}
|
|
212
217
|
|
|
213
218
|
// fetch!
|
package/src/lib/RedisCache.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Redis from 'ioredis';
|
|
2
|
-
import
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
3
|
|
|
4
4
|
import { CachableValue, CacheInstance, Lock } from './CacheInstance';
|
|
5
5
|
|
|
@@ -26,23 +26,15 @@ 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
|
|
34
|
-
public static REDLOCK_JITTER_MS = parseInt(process.env.REDLOCK_JITTER_MS as string, 10) || 200; // lib. default: 200
|
|
29
|
+
public static LOCK_MAX_ATTEMPTS =
|
|
30
|
+
parseInt(process.env.REDLOCK_RETRY_COUNT as string, 10) || RedisCache.LOCK_RETRY_COUNT;
|
|
31
|
+
public static LOCK_RETRY_DELAY =
|
|
32
|
+
parseInt(process.env.REDLOCK_RETRY_DELAY_MS as string, 10) || RedisCache.LOCK_RETRY_DELAY_MS;
|
|
33
|
+
public static LOCK_JITTER_MS = parseInt(process.env.REDLOCK_JITTER_MS as string, 10) || 200;
|
|
35
34
|
|
|
36
35
|
private redisClient: Redis;
|
|
37
36
|
private ready = false;
|
|
38
37
|
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;
|
|
46
38
|
|
|
47
39
|
constructor(redisUrl: string, readOnly = false) {
|
|
48
40
|
super();
|
|
@@ -63,28 +55,10 @@ export class RedisCache extends CacheInstance {
|
|
|
63
55
|
// This prevents get/setValue calls from hanging if there is no active connection
|
|
64
56
|
enableOfflineQueue: false,
|
|
65
57
|
});
|
|
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
|
-
});
|
|
80
58
|
|
|
81
59
|
this.redisClient.on('ready', this.startConnectionStrategy.bind(this));
|
|
82
60
|
this.redisClient.on('end', this.endConnectionStrategy.bind(this));
|
|
83
61
|
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));
|
|
88
62
|
}
|
|
89
63
|
|
|
90
64
|
/**
|
|
@@ -113,10 +87,6 @@ export class RedisCache extends CacheInstance {
|
|
|
113
87
|
this.emit('warn', 'Error while connected to the Redis cache!');
|
|
114
88
|
}
|
|
115
89
|
|
|
116
|
-
public redlockErrorStrategy(err: any): void {
|
|
117
|
-
this.emit('warn', 'Redlock error:', err);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
90
|
/**
|
|
121
91
|
* The end event is emitted by the redis client when an
|
|
122
92
|
* established connection has ended.
|
|
@@ -368,8 +338,6 @@ export class RedisCache extends CacheInstance {
|
|
|
368
338
|
|
|
369
339
|
/**
|
|
370
340
|
* @inheritdoc
|
|
371
|
-
* Locking through the redlock algorithm
|
|
372
|
-
* https://redis.io/topics/distlock
|
|
373
341
|
*/
|
|
374
342
|
public isLockingSupported(): boolean {
|
|
375
343
|
return true;
|
|
@@ -379,13 +347,33 @@ export class RedisCache extends CacheInstance {
|
|
|
379
347
|
* @inheritdoc
|
|
380
348
|
*/
|
|
381
349
|
public async lock(resource: string, ttlMs: number, retry = true): Promise<Lock> {
|
|
382
|
-
const
|
|
383
|
-
const
|
|
350
|
+
const maxAttempts = retry === false ? 1 : RedisCache.LOCK_MAX_ATTEMPTS;
|
|
351
|
+
const value = randomUUID();
|
|
352
|
+
|
|
353
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
354
|
+
const result = await this.redisClient.set(resource, value, 'PX', ttlMs, 'NX');
|
|
355
|
+
if (result === 'OK') {
|
|
356
|
+
return {
|
|
357
|
+
value,
|
|
358
|
+
unlock: async () => {
|
|
359
|
+
await this.redisClient.eval(
|
|
360
|
+
'if redis.call("get", KEYS[1]) == ARGV[1] then return redis.call("del", KEYS[1]) else return 0 end',
|
|
361
|
+
1,
|
|
362
|
+
resource,
|
|
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
|
+
}
|
|
384
375
|
|
|
385
|
-
|
|
386
|
-
value: internalLock.value,
|
|
387
|
-
unlock: async () => internalLock.unlock(),
|
|
388
|
-
};
|
|
376
|
+
throw new Error(`Failed to acquire lock on ${resource} after ${maxAttempts} attempts`);
|
|
389
377
|
}
|
|
390
378
|
|
|
391
379
|
/**
|
package/test/CacheClient_test.ts
CHANGED
|
@@ -328,16 +328,4 @@ 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
|
-
});
|
|
343
331
|
});
|
|
@@ -411,6 +411,13 @@ function runTests(name: string, cache: CacheInstance): void {
|
|
|
411
411
|
expect(await cache.hasLock(prefix)).to.be.false;
|
|
412
412
|
});
|
|
413
413
|
|
|
414
|
+
ifLockIt('unlocking an already-expired lock does not throw', async () => {
|
|
415
|
+
const resource = `lock_${Math.random()}`;
|
|
416
|
+
const lock = await cache.lock(resource, 50);
|
|
417
|
+
await sleep(51);
|
|
418
|
+
await cache.unlock(lock);
|
|
419
|
+
});
|
|
420
|
+
|
|
414
421
|
ifLockIt('locks before fetching if value not in cache', async () => {
|
|
415
422
|
const key = `key${Math.random()}`;
|
|
416
423
|
let numCalled = 0;
|
|
@@ -508,7 +515,9 @@ function runTests(name: string, cache: CacheInstance): void {
|
|
|
508
515
|
}
|
|
509
516
|
|
|
510
517
|
expect(thrownError).to.exist;
|
|
511
|
-
expect(thrownError!.message).to.include(
|
|
518
|
+
expect(thrownError!.message).to.include(
|
|
519
|
+
`Failed to acquire lock for key ${key}. No active fetch or cached value found: Lock acquisition failed`,
|
|
520
|
+
);
|
|
512
521
|
|
|
513
522
|
// Restore and recreate the spy
|
|
514
523
|
lockStub.restore();
|