cachette 4.0.14 → 4.0.16

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.
@@ -1,7 +1,17 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
  export type CachableValue = any;
3
3
  export type FetchingFunction = () => Promise<CachableValue>;
4
+ /**
5
+ * Represents a lock on a resource.
6
+ * The lock object must be passed to unlock() to release the lock.
7
+ */
8
+ export interface Lock {
9
+ value: string | null;
10
+ unlock(): Promise<void>;
11
+ }
4
12
  export declare abstract class CacheInstance extends EventEmitter {
13
+ static LOCK_RETRY_COUNT: number;
14
+ static LOCK_RETRY_DELAY_MS: number;
5
15
  /**
6
16
  * Will resolve when the cache instance connection is ready.
7
17
  */
@@ -76,15 +86,15 @@ export declare abstract class CacheInstance extends EventEmitter {
76
86
  * @param ttlMs The time to live of the lock in ms
77
87
  * @param retry Whether or not to retry attempts to lock
78
88
  *
79
- * @returns The lock, an opaque object that must be passed to unlock()
89
+ * @returns The lock object that must be passed to unlock()
80
90
  */
81
- lock(resource: string, ttlMs: number, retry?: boolean): Promise<any>;
91
+ lock(resource: string, ttlMs: number, retry?: boolean): Promise<Lock>;
82
92
  /**
83
- * Unlock a named resource aquired with lock()
93
+ * Unlock a named resource acquired with lock()
84
94
  *
85
95
  * @param lock The lock object
86
96
  */
87
- unlock(lock: any): Promise<void>;
97
+ unlock(lock: Lock): Promise<void>;
88
98
  /**
89
99
  * Determine whether *at least one non-expired lock* starts with the given pattern.
90
100
  */
@@ -98,6 +108,7 @@ export declare abstract class CacheInstance extends EventEmitter {
98
108
  * simultaneous requests to the same resource in parallel.
99
109
  */
100
110
  private activeFetches;
111
+ private getValueWithErrorHandling;
101
112
  /**
102
113
  * Get or fetch a value
103
114
  *
@@ -3,6 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CacheInstance = void 0;
4
4
  const node_events_1 = require("node:events");
5
5
  class CacheInstance extends node_events_1.EventEmitter {
6
+ // Shared lock configuration with generic env vars
7
+ static LOCK_RETRY_COUNT = parseInt(process.env.CACHETTE_LOCK_RETRY_COUNT, 10) || 20;
8
+ static LOCK_RETRY_DELAY_MS = parseInt(process.env.CACHETTE_LOCK_RETRY_DELAY_MS, 10) || 200;
6
9
  /**
7
10
  * Determines if locking is supported in the cache implementation
8
11
  */
@@ -16,18 +19,18 @@ class CacheInstance extends node_events_1.EventEmitter {
16
19
  * @param ttlMs The time to live of the lock in ms
17
20
  * @param retry Whether or not to retry attempts to lock
18
21
  *
19
- * @returns The lock, an opaque object that must be passed to unlock()
22
+ * @returns The lock object that must be passed to unlock()
20
23
  */
21
24
  lock(resource, ttlMs, retry) {
22
25
  throw new Error('unsupported');
23
26
  }
24
27
  /**
25
- * Unlock a named resource aquired with lock()
28
+ * Unlock a named resource acquired with lock()
26
29
  *
27
30
  * @param lock The lock object
28
31
  */
29
- unlock(lock) {
30
- throw new Error('unsupported');
32
+ async unlock(lock) {
33
+ await lock.unlock();
31
34
  }
32
35
  /**
33
36
  * Determine whether *at least one non-expired lock* starts with the given pattern.
@@ -48,6 +51,18 @@ class CacheInstance extends node_events_1.EventEmitter {
48
51
  * simultaneous requests to the same resource in parallel.
49
52
  */
50
53
  activeFetches = {};
54
+ async getValueWithErrorHandling(key, shouldCacheError) {
55
+ const cached = await this.getValue(key);
56
+ if (cached instanceof Error) {
57
+ if (shouldCacheError && shouldCacheError(cached)) {
58
+ throw cached;
59
+ }
60
+ else {
61
+ return undefined;
62
+ }
63
+ }
64
+ return cached;
65
+ }
51
66
  /**
52
67
  * Get or fetch a value
53
68
  *
@@ -63,15 +78,7 @@ class CacheInstance extends node_events_1.EventEmitter {
63
78
  */
64
79
  async getOrFetchValue(key, ttl, fetchFunction, lockTtl, shouldCacheError) {
65
80
  // already cached?
66
- let cached = await this.getValue(key);
67
- if (cached instanceof Error) {
68
- if (shouldCacheError) {
69
- throw cached;
70
- }
71
- else {
72
- cached = undefined;
73
- }
74
- }
81
+ let cached = await this.getValueWithErrorHandling(key, shouldCacheError);
75
82
  if (cached !== undefined) {
76
83
  return cached;
77
84
  }
@@ -80,54 +87,61 @@ class CacheInstance extends node_events_1.EventEmitter {
80
87
  if (currentFetch) {
81
88
  return currentFetch;
82
89
  }
83
- // I'm the one fetching.
84
- let lock;
85
- try {
86
- // get the lock if needed
87
- const lockName = `lock__${key}`;
88
- if (lockTtl && this.isLockingSupported()) {
89
- lock = await this.lock(lockName, lockTtl * 1000);
90
- // check if the value has been populated while we were locking
91
- let cachedValue = await this.getValue(key);
92
- if (cachedValue instanceof Error) {
93
- if (shouldCacheError) {
94
- throw cachedValue;
90
+ // I'm the one fetching - immediately register the fetch promise to prevent race conditions
91
+ this.activeFetches[key] = (async () => {
92
+ let lock;
93
+ let lockErrorMessage;
94
+ try {
95
+ // get the lock if needed
96
+ if (lockTtl && this.isLockingSupported()) {
97
+ const lockName = `lock__${key}`;
98
+ try {
99
+ lock = await this.lock(lockName, lockTtl * 1000);
95
100
  }
96
- else {
97
- cachedValue = undefined;
101
+ catch (lockError) {
102
+ lockErrorMessage = lockError instanceof Error ? lockError.message : String(lockError);
98
103
  }
99
104
  }
105
+ // check gain if the value has been populated while we previously checked
106
+ const cachedValue = await this.getValueWithErrorHandling(key, shouldCacheError);
100
107
  if (cachedValue !== undefined) {
101
108
  return cachedValue;
102
109
  }
110
+ if (lockErrorMessage) {
111
+ throw new Error(`Failed to acquire lock for key ${key}. No active fetch or cached value found: ${lockErrorMessage}`);
112
+ }
113
+ // fetch!
114
+ let error;
115
+ let result;
116
+ try {
117
+ result = await fetchFunction();
118
+ }
119
+ catch (err) {
120
+ error = err;
121
+ }
122
+ // cache! results: always, errors: only if satisfying user assertion
123
+ if (error && shouldCacheError && shouldCacheError(error)) {
124
+ await this.setValue(key, error, ttl);
125
+ }
126
+ else if (result !== undefined) {
127
+ await this.setValue(key, result, ttl);
128
+ }
129
+ if (error) {
130
+ throw error;
131
+ }
132
+ return result;
103
133
  }
104
- // fetch!
105
- let error;
106
- let result;
107
- try {
108
- const fetchPromise = (this.activeFetches[key] = fetchFunction());
109
- result = await fetchPromise;
110
- }
111
- catch (err) {
112
- error = err;
113
- }
114
- // cache! results: always, errors: only if satisfying user assertion
115
- if (error && shouldCacheError && shouldCacheError(error)) {
116
- await this.setValue(key, error, ttl);
117
- }
118
- else if (result !== undefined) {
119
- await this.setValue(key, result, ttl);
120
- }
121
- if (error) {
122
- throw error;
134
+ finally {
135
+ if (lock) {
136
+ await this.unlock(lock);
137
+ }
123
138
  }
124
- return result;
139
+ })();
140
+ try {
141
+ return await this.activeFetches[key];
125
142
  }
126
143
  finally {
127
144
  delete this.activeFetches[key];
128
- if (lock) {
129
- await this.unlock(lock);
130
- }
131
145
  }
132
146
  }
133
147
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CacheInstance.js","sourceRoot":"","sources":["../../../src/lib/CacheInstance.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CacheInstance.js","sourceRoot":"","sources":["../../../src/lib/CacheInstance.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,7 @@
1
- import { CachableValue, CacheInstance } from './CacheInstance';
1
+ import { CachableValue, CacheInstance, Lock } from './CacheInstance';
2
2
  export declare class LocalCache extends CacheInstance {
3
3
  static DEFAULT_MAX_ITEMS: number;
4
4
  static DEFAULT_MAX_AGE: number;
5
- static LOCK_ACQUIRE_TIMEOUT: number;
6
5
  private cache;
7
6
  /**
8
7
  * @inheritdoc
@@ -52,11 +51,7 @@ export declare class LocalCache extends CacheInstance {
52
51
  /**
53
52
  * @inheritdoc
54
53
  */
55
- lock(resource: string, ttlMs: number): Promise<any>;
56
- /**
57
- * @inheritdoc
58
- */
59
- unlock(lock: any): Promise<void>;
54
+ lock(resource: string, ttlMs: number, retry?: boolean): Promise<Lock>;
60
55
  /**
61
56
  * @inheritdoc
62
57
  *
@@ -10,7 +10,6 @@ class LocalCache extends CacheInstance_1.CacheInstance {
10
10
  static DEFAULT_MAX_ITEMS = 5000;
11
11
  // Default maximum age for the items, in MS.
12
12
  static DEFAULT_MAX_AGE = 30 * 60 * 1000;
13
- static LOCK_ACQUIRE_TIMEOUT = 2000;
14
13
  // See https://github.com/isaacs/node-lru-cache#options
15
14
  // for options.
16
15
  cache = new lru_cache_1.LRUCache({
@@ -108,36 +107,26 @@ class LocalCache extends CacheInstance_1.CacheInstance {
108
107
  /**
109
108
  * @inheritdoc
110
109
  */
111
- async lock(resource, ttlMs) {
112
- let isLocked = true;
113
- const startTimestamp = Date.now();
114
- while (isLocked) {
115
- if (Date.now() - startTimestamp > LocalCache.LOCK_ACQUIRE_TIMEOUT) {
116
- throw new Error(`Abandoning locking ${resource} , as timed out while waiting for other lock to be released.`);
117
- }
110
+ async lock(resource, ttlMs, retry = true) {
111
+ const maxAttempts = retry ? LocalCache.LOCK_RETRY_COUNT : 1;
112
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
118
113
  this.cache.purgeStale();
119
114
  if (!this.cache.has(resource)) {
120
- isLocked = false;
115
+ // Lock acquired
116
+ const lockValue = `local-${Date.now()}-${Math.random().toString(36).slice(2)}`;
117
+ this.cache.set(resource, lockValue, { ttl: ttlMs });
118
+ return {
119
+ value: lockValue,
120
+ unlock: async () => {
121
+ this.cache.delete(resource);
122
+ },
123
+ };
121
124
  }
122
- else {
123
- // LRU keeps its TTL information private, so we don't know how long to wait.
124
- // Whatever, we just loop on waiting a bit and retrying.
125
- await sleep(10);
125
+ if (attempt < maxAttempts - 1) {
126
+ await sleep(LocalCache.LOCK_RETRY_DELAY_MS);
126
127
  }
127
128
  }
128
- this.cache.set(resource, 1, { ttl: ttlMs });
129
- return new Promise((resolve) => {
130
- resolve(resource);
131
- });
132
- }
133
- /**
134
- * @inheritdoc
135
- */
136
- async unlock(lock) {
137
- this.cache.delete(lock);
138
- return new Promise((resolve) => {
139
- resolve();
140
- });
129
+ throw new Error(`Failed to acquire lock on ${resource} after ${maxAttempts} attempts`);
141
130
  }
142
131
  /**
143
132
  * @inheritdoc
@@ -1 +1 @@
1
- {"version":3,"file":"LocalCache.js","sourceRoot":"","sources":["../../../src/lib/LocalCache.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LocalCache.js","sourceRoot":"","sources":["../../../src/lib/LocalCache.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,5 @@
1
- import { CachableValue, CacheInstance } from './CacheInstance';
1
+ import { CachableValue, CacheInstance, Lock } from './CacheInstance';
2
2
  export declare const SIZE_THRESHOLD_WARNING_BYTES = 20000000;
3
- export interface Lock {
4
- value: string | null;
5
- unlock(): Promise<void>;
6
- }
7
3
  /**
8
4
  * Wrapper class for using Redis as a cache.
9
5
  *
@@ -123,10 +119,6 @@ export declare class RedisCache extends CacheInstance {
123
119
  * @inheritdoc
124
120
  */
125
121
  lock(resource: string, ttlMs: number, retry?: boolean): Promise<Lock>;
126
- /**
127
- * @inheritdoc
128
- */
129
- unlock(lock: Lock): Promise<void>;
130
122
  /**
131
123
  * @inheritdoc
132
124
  *
@@ -24,8 +24,9 @@ class RedisCache extends CacheInstance_1.CacheInstance {
24
24
  static ERROR_PREFIX = 'f405eed4-507c-4aa5-a6d2-c1813d584b8f-ERROR';
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
- static REDLOCK_RETRY_COUNT = parseInt(process.env.REDLOCK_RETRY_COUNT, 10) || 20; // lib. default: 10
28
- static REDLOCK_RETRY_DELAY_MS = parseInt(process.env.REDLOCK_RETRY_DELAY_MS, 10) || 200; // lib. default: 200
27
+ // Backward compatible: REDLOCK_* takes precedence, then CACHETTE_LOCK_*
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
29
30
  static REDLOCK_CLOCK_DRIFT_FACTOR = parseInt(process.env.REDLOCK_CLOCK_DRIFT_FACTOR, 10) || 0.01; // lib. default: 0.01
30
31
  static REDLOCK_JITTER_MS = parseInt(process.env.REDLOCK_JITTER_MS, 10) || 200; // lib. default: 200
31
32
  redisClient;
@@ -341,12 +342,6 @@ class RedisCache extends CacheInstance_1.CacheInstance {
341
342
  unlock: async () => internalLock.unlock(),
342
343
  };
343
344
  }
344
- /**
345
- * @inheritdoc
346
- */
347
- async unlock(lock) {
348
- await lock.unlock();
349
- }
350
345
  /**
351
346
  * @inheritdoc
352
347
  *
@@ -1 +1 @@
1
- {"version":3,"file":"RedisCache.js","sourceRoot":"","sources":["../../../src/lib/RedisCache.ts"],"names":[],"mappings":"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"}
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.14",
3
+ "version": "4.0.16",
4
4
  "engines": {
5
5
  "node": ">=20",
6
6
  "npm": ">=10"
@@ -3,7 +3,19 @@ import { EventEmitter } from 'node:events';
3
3
  export type CachableValue = any;
4
4
  export type FetchingFunction = () => Promise<CachableValue>;
5
5
 
6
+ /**
7
+ * Represents a lock on a resource.
8
+ * The lock object must be passed to unlock() to release the lock.
9
+ */
10
+ export interface Lock {
11
+ value: string | null;
12
+ unlock(): Promise<void>;
13
+ }
14
+
6
15
  export abstract class CacheInstance extends EventEmitter {
16
+ // Shared lock configuration with generic env vars
17
+ public static LOCK_RETRY_COUNT = parseInt(process.env.CACHETTE_LOCK_RETRY_COUNT as string, 10) || 20;
18
+ public static LOCK_RETRY_DELAY_MS = parseInt(process.env.CACHETTE_LOCK_RETRY_DELAY_MS as string, 10) || 200;
7
19
  /**
8
20
  * Will resolve when the cache instance connection is ready.
9
21
  */
@@ -90,19 +102,19 @@ export abstract class CacheInstance extends EventEmitter {
90
102
  * @param ttlMs The time to live of the lock in ms
91
103
  * @param retry Whether or not to retry attempts to lock
92
104
  *
93
- * @returns The lock, an opaque object that must be passed to unlock()
105
+ * @returns The lock object that must be passed to unlock()
94
106
  */
95
- public lock(resource: string, ttlMs: number, retry?: boolean): Promise<any> {
107
+ public lock(resource: string, ttlMs: number, retry?: boolean): Promise<Lock> {
96
108
  throw new Error('unsupported');
97
109
  }
98
110
 
99
111
  /**
100
- * Unlock a named resource aquired with lock()
112
+ * Unlock a named resource acquired with lock()
101
113
  *
102
114
  * @param lock The lock object
103
115
  */
104
- public unlock(lock: any): Promise<void> {
105
- throw new Error('unsupported');
116
+ public async unlock(lock: Lock): Promise<void> {
117
+ await lock.unlock();
106
118
  }
107
119
 
108
120
  /**
@@ -127,6 +139,19 @@ export abstract class CacheInstance extends EventEmitter {
127
139
  */
128
140
  private activeFetches: { [key: string]: Promise<CachableValue> } = {};
129
141
 
142
+ private async getValueWithErrorHandling(key: string, shouldCacheError?: (err: Error) => boolean): Promise<CachableValue> {
143
+ const cached = await this.getValue(key);
144
+ if (cached instanceof Error) {
145
+ if (shouldCacheError && shouldCacheError(cached)) {
146
+ throw cached;
147
+ } else {
148
+ return undefined;
149
+ }
150
+ }
151
+
152
+ return cached;
153
+ }
154
+
130
155
  /**
131
156
  * Get or fetch a value
132
157
  *
@@ -148,14 +173,7 @@ export abstract class CacheInstance extends EventEmitter {
148
173
  shouldCacheError?: (err: Error) => boolean,
149
174
  ): Promise<ReturnType<F>> {
150
175
  // already cached?
151
- let cached = await this.getValue(key);
152
- if (cached instanceof Error) {
153
- if (shouldCacheError) {
154
- throw cached;
155
- } else {
156
- cached = undefined;
157
- }
158
- }
176
+ let cached = await this.getValueWithErrorHandling(key, shouldCacheError);
159
177
  if (cached !== undefined) {
160
178
  return cached;
161
179
  }
@@ -166,53 +184,63 @@ export abstract class CacheInstance extends EventEmitter {
166
184
  return currentFetch;
167
185
  }
168
186
 
169
- // I'm the one fetching.
170
- let lock: any;
171
- try {
172
- // get the lock if needed
173
- const lockName = `lock__${key}`;
174
- if (lockTtl && this.isLockingSupported()) {
175
- lock = await this.lock(lockName, lockTtl * 1000);
176
- // check if the value has been populated while we were locking
177
- let cachedValue = await this.getValue(key);
178
- if (cachedValue instanceof Error) {
179
- if (shouldCacheError) {
180
- throw cachedValue;
181
- } else {
182
- cachedValue = undefined;
187
+ // I'm the one fetching - immediately register the fetch promise to prevent race conditions
188
+ this.activeFetches[key] = (async () => {
189
+ let lock: Lock | undefined;
190
+ let lockErrorMessage: string | undefined;
191
+
192
+ try {
193
+ // get the lock if needed
194
+ if (lockTtl && this.isLockingSupported()) {
195
+ const lockName = `lock__${key}`;
196
+ try {
197
+ lock = await this.lock(lockName, lockTtl * 1000);
198
+ } catch (lockError) {
199
+ lockErrorMessage = lockError instanceof Error ? lockError.message : String(lockError);
183
200
  }
184
201
  }
202
+
203
+ // check gain if the value has been populated while we previously checked
204
+ const cachedValue = await this.getValueWithErrorHandling(key, shouldCacheError);
185
205
  if (cachedValue !== undefined) {
186
206
  return cachedValue;
187
207
  }
188
- }
189
208
 
190
- // fetch!
191
- let error: Error | undefined;
192
- let result: any;
193
- try {
194
- const fetchPromise = (this.activeFetches[key] = fetchFunction());
195
- result = await fetchPromise;
196
- } catch (err) {
197
- error = err;
198
- }
209
+ if (lockErrorMessage) {
210
+ throw new Error(`Failed to acquire lock for key ${key}. No active fetch or cached value found: ${lockErrorMessage}`);
211
+ }
199
212
 
200
- // cache! results: always, errors: only if satisfying user assertion
201
- if (error && shouldCacheError && shouldCacheError(error)) {
202
- await this.setValue(key, error, ttl);
203
- } else if (result !== undefined) {
204
- await this.setValue(key, result, ttl);
205
- }
213
+ // fetch!
214
+ let error: Error | undefined;
215
+ let result: any;
216
+ try {
217
+ result = await fetchFunction();
218
+ } catch (err) {
219
+ error = err;
220
+ }
221
+
222
+ // cache! results: always, errors: only if satisfying user assertion
223
+ if (error && shouldCacheError && shouldCacheError(error)) {
224
+ await this.setValue(key, error, ttl);
225
+ } else if (result !== undefined) {
226
+ await this.setValue(key, result, ttl);
227
+ }
206
228
 
207
- if (error) {
208
- throw error;
229
+ if (error) {
230
+ throw error;
231
+ }
232
+ return result;
233
+ } finally {
234
+ if (lock) {
235
+ await this.unlock(lock);
236
+ }
209
237
  }
210
- return result;
238
+ })();
239
+
240
+ try {
241
+ return await this.activeFetches[key];
211
242
  } finally {
212
243
  delete this.activeFetches[key];
213
- if (lock) {
214
- await this.unlock(lock);
215
- }
216
244
  }
217
245
  }
218
246
  }
@@ -1,6 +1,6 @@
1
1
  import { LRUCache } from 'lru-cache';
2
2
 
3
- import { CachableValue, CacheInstance } from './CacheInstance';
3
+ import { CachableValue, CacheInstance, Lock } from './CacheInstance';
4
4
 
5
5
  async function sleep(ms: number): Promise<void> {
6
6
  return new Promise((resolve) => setTimeout(resolve, ms));
@@ -11,8 +11,6 @@ export class LocalCache extends CacheInstance {
11
11
  // Default maximum age for the items, in MS.
12
12
  public static DEFAULT_MAX_AGE: number = 30 * 60 * 1000;
13
13
 
14
- public static LOCK_ACQUIRE_TIMEOUT = 2000;
15
-
16
14
  // See https://github.com/isaacs/node-lru-cache#options
17
15
  // for options.
18
16
  private cache = new LRUCache<string, any>({
@@ -123,36 +121,30 @@ export class LocalCache extends CacheInstance {
123
121
  /**
124
122
  * @inheritdoc
125
123
  */
126
- public async lock(resource: string, ttlMs: number): Promise<any> {
127
- let isLocked = true;
128
- const startTimestamp = Date.now();
129
- while (isLocked) {
130
- if (Date.now() - startTimestamp > LocalCache.LOCK_ACQUIRE_TIMEOUT) {
131
- throw new Error(`Abandoning locking ${resource} , as timed out while waiting for other lock to be released.`);
132
- }
124
+ public async lock(resource: string, ttlMs: number, retry = true): Promise<Lock> {
125
+ const maxAttempts = retry ? LocalCache.LOCK_RETRY_COUNT : 1;
126
+
127
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
133
128
  this.cache.purgeStale();
134
129
  if (!this.cache.has(resource)) {
135
- isLocked = false;
136
- } else {
137
- // LRU keeps its TTL information private, so we don't know how long to wait.
138
- // Whatever, we just loop on waiting a bit and retrying.
139
- await sleep(10);
130
+ // Lock acquired
131
+ const lockValue = `local-${Date.now()}-${Math.random().toString(36).slice(2)}`;
132
+ this.cache.set(resource, lockValue, { ttl: ttlMs });
133
+
134
+ return {
135
+ value: lockValue,
136
+ unlock: async () => {
137
+ this.cache.delete(resource);
138
+ },
139
+ };
140
+ }
141
+
142
+ if (attempt < maxAttempts - 1) {
143
+ await sleep(LocalCache.LOCK_RETRY_DELAY_MS);
140
144
  }
141
145
  }
142
- this.cache.set(resource, 1, { ttl: ttlMs });
143
- return new Promise((resolve) => {
144
- resolve(resource);
145
- });
146
- }
147
146
 
148
- /**
149
- * @inheritdoc
150
- */
151
- public async unlock(lock: any): Promise<void> {
152
- this.cache.delete(lock);
153
- return new Promise((resolve) => {
154
- resolve();
155
- });
147
+ throw new Error(`Failed to acquire lock on ${resource} after ${maxAttempts} attempts`);
156
148
  }
157
149
 
158
150
  /**
@@ -1,15 +1,10 @@
1
1
  import Redis from 'ioredis';
2
2
  import * as Redlock from 'redlock';
3
3
 
4
- import { CachableValue, CacheInstance } from './CacheInstance';
4
+ import { CachableValue, CacheInstance, Lock } from './CacheInstance';
5
5
 
6
6
  export const SIZE_THRESHOLD_WARNING_BYTES = 20_000_000;
7
7
 
8
- export interface Lock {
9
- value: string | null;
10
- unlock(): Promise<void>;
11
- }
12
-
13
8
  /**
14
9
  * Wrapper class for using Redis as a cache.
15
10
  *
@@ -30,8 +25,11 @@ export class RedisCache extends CacheInstance {
30
25
  public static NUMBER_PREFIX = 'f405eed4-507c-4aa5-a6d2-c1813d584b8f-NUMBER';
31
26
 
32
27
  public static REDIS_CONNECTION_TIMEOUT_MS = parseInt(process.env.REDIS_CONNECTION_TIMEOUT_MS as string, 10) || 5000;
33
- public static REDLOCK_RETRY_COUNT = parseInt(process.env.REDLOCK_RETRY_COUNT as string, 10) || 20; // lib. default: 10
34
- public static REDLOCK_RETRY_DELAY_MS = parseInt(process.env.REDLOCK_RETRY_DELAY_MS as string, 10) || 200; // lib. default: 200
28
+ // Backward compatible: REDLOCK_* takes precedence, then CACHETTE_LOCK_*
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
35
33
  public static REDLOCK_CLOCK_DRIFT_FACTOR = parseInt(process.env.REDLOCK_CLOCK_DRIFT_FACTOR as string, 10) || 0.01; // lib. default: 0.01
36
34
  public static REDLOCK_JITTER_MS = parseInt(process.env.REDLOCK_JITTER_MS as string, 10) || 200; // lib. default: 200
37
35
 
@@ -390,13 +388,6 @@ export class RedisCache extends CacheInstance {
390
388
  };
391
389
  }
392
390
 
393
- /**
394
- * @inheritdoc
395
- */
396
- public async unlock(lock: Lock): Promise<void> {
397
- await lock.unlock();
398
- }
399
-
400
391
  /**
401
392
  * @inheritdoc
402
393
  *
@@ -132,6 +132,50 @@ describe('CacheClient', () => {
132
132
  expect(myObj.numCalled).to.equal(2); // from cache -> NO increase
133
133
  });
134
134
 
135
+ it('correctly evaluates shouldCacheError callback when retrieving cached errors', async () => {
136
+ const cache = new LocalCache();
137
+ const key = 'test-key';
138
+
139
+ // Manually cache an error with a specific property
140
+ const cachedError = new Error('cached error');
141
+ cachedError['errorType'] = 'temporary';
142
+ await cache.setValue(key, cachedError, 60);
143
+
144
+ // Try to retrieve with a shouldCacheError that should reject this error
145
+ const result = await cache.getOrFetchValue(
146
+ key,
147
+ 60,
148
+ async () => 'fresh value',
149
+ undefined,
150
+ (err) => err['errorType'] === 'permanent', // Only cache permanent errors
151
+ );
152
+
153
+ // Should return 'fresh value' because the cached error doesn't match the callback criteria
154
+ expect(result).to.equal('fresh value');
155
+
156
+ // Now try with a callback that accepts the cached error
157
+ const cachedError2 = new Error('cached error 2');
158
+ cachedError2['errorType'] = 'permanent';
159
+ await cache.setValue(key, cachedError2, 60);
160
+
161
+ let didThrow = false;
162
+ try {
163
+ await cache.getOrFetchValue(
164
+ key,
165
+ 60,
166
+ async () => 'fresh value',
167
+ undefined,
168
+ (err) => err['errorType'] === 'permanent', // Only cache permanent errors
169
+ );
170
+ } catch (err) {
171
+ didThrow = true;
172
+ expect(err.message).to.equal('cached error 2');
173
+ }
174
+
175
+ // Should throw because the cached error matches the callback criteria
176
+ expect(didThrow).to.be.true;
177
+ });
178
+
135
179
  it('protect against concurrent fetches', async () => {
136
180
  const myObj = new MyClass();
137
181
  const jobs: Promise<any>[] = [];
@@ -456,5 +456,63 @@ function runTests(name: string, cache: CacheInstance): void {
456
456
  sinon.assert.calledTwice(lockSpy); // includes our own call above
457
457
  sinon.assert.calledTwice(unlockSpy);
458
458
  });
459
+
460
+ ifLockIt('returns cached value if lock acquisition fails and value was populated meanwhile', async () => {
461
+ const key = `key${Math.random()}`;
462
+ let numCalled = 0;
463
+ const object = {
464
+ fetch: async (v) => {
465
+ numCalled++;
466
+ return v;
467
+ },
468
+ };
469
+
470
+ const fetchFunction = object.fetch.bind(object, 'newvalue');
471
+
472
+ // Restore the spy temporarily so we can stub it
473
+ lockSpy.restore();
474
+
475
+ const lockStub = sinon.stub(cache, 'lock').callsFake(async () => {
476
+ // Before failing, simulate the cache being populated
477
+ await cache.setValue(key, 'from-cache');
478
+ throw new Error('Lock acquisition failed');
479
+ });
480
+
481
+ const value = await cache.getOrFetchValue(key, 10, fetchFunction, 1);
482
+
483
+ expect(value).to.eql('from-cache');
484
+ expect(numCalled).to.eql(0); // never called fetch, got from cache
485
+
486
+ lockStub.restore();
487
+ lockSpy = sinon.spy(cache, 'lock');
488
+ });
489
+
490
+ ifLockIt('throws detailed error if lock fails with no activeFetch or cached value', async () => {
491
+ const key = `key${Math.random()}`;
492
+ const object = {
493
+ fetch: async (v) => v,
494
+ };
495
+
496
+ const fetchFunction = object.fetch.bind(object, 'newvalue');
497
+
498
+ // Restore the spy temporarily so we can stub it
499
+ lockSpy.restore();
500
+
501
+ const lockStub = sinon.stub(cache, 'lock').rejects(new Error('Lock acquisition failed'));
502
+
503
+ let thrownError: Error | undefined;
504
+ try {
505
+ await cache.getOrFetchValue(key, 10, fetchFunction, 1);
506
+ } catch (err) {
507
+ thrownError = err as Error;
508
+ }
509
+
510
+ expect(thrownError).to.exist;
511
+ expect(thrownError!.message).to.include(`Failed to acquire lock for key ${key}. No active fetch or cached value found: Lock acquisition failed`);
512
+
513
+ // Restore and recreate the spy
514
+ lockStub.restore();
515
+ lockSpy = sinon.spy(cache, 'lock');
516
+ });
459
517
  });
460
518
  }
@@ -1,6 +1,8 @@
1
1
  import { expect } from 'chai';
2
+ import * as sinon from 'sinon';
2
3
 
3
4
  import { LocalCache } from '../src/lib/LocalCache';
5
+ import { CacheInstance } from '../src/lib/CacheInstance';
4
6
 
5
7
  describe('LocalCache', () => {
6
8
  it('can set values', async () => {
@@ -115,6 +117,105 @@ describe('LocalCache', () => {
115
117
  expect(wasSet).to.be.true;
116
118
  expect(cacheTtl).to.equal(0);
117
119
  });
120
+
121
+ describe('lock', () => {
122
+ it('returns a Lock object with value property and unlock method', async () => {
123
+ const cache = new LocalCache();
124
+ const lock = await cache.lock('test-resource', 10000);
125
+
126
+ expect(lock).to.have.property('value');
127
+ expect(lock.value).to.be.a('string');
128
+ expect(lock.value).to.match(/^local-\d+-[a-z0-9]+$/);
129
+
130
+ expect(lock).to.have.property('unlock');
131
+ expect(lock.unlock).to.be.a('function');
132
+
133
+ await cache.unlock(lock);
134
+ });
135
+
136
+ it('releases lock via the returned Lock object unlock method', async () => {
137
+ const cache = new LocalCache();
138
+ const resource = `test-resource-${Math.random()}`;
139
+
140
+ const lock = await cache.lock(resource, 10000);
141
+ expect(await cache.hasLock(resource)).to.be.true;
142
+
143
+ await lock.unlock();
144
+ expect(await cache.hasLock(resource)).to.be.false;
145
+ });
146
+
147
+ it('releases lock via cache.unlock()', async () => {
148
+ const cache = new LocalCache();
149
+ const resource = `test-resource-${Math.random()}`;
150
+
151
+ const lock = await cache.lock(resource, 10000);
152
+ expect(await cache.hasLock(resource)).to.be.true;
153
+
154
+ await cache.unlock(lock);
155
+ expect(await cache.hasLock(resource)).to.be.false;
156
+ });
157
+
158
+ it('with retry = true, retries until lock is available', async () => {
159
+ // Fake only setTimeout to avoid conflicts with LRU cache's TTL (which uses Date)
160
+ const clock = sinon.useFakeTimers({ toFake: ['setTimeout'] });
161
+
162
+ try {
163
+ const resource = 'test-resource';
164
+ const cache = new LocalCache();
165
+ const hasSpy = sinon.spy(cache['cache'], 'has');
166
+
167
+ const firstLock = await cache.lock(resource, 10000);
168
+ const hasCallsAfterFirstLock = hasSpy.callCount;
169
+
170
+ let secondLockAcquired = false;
171
+ const lockPromise = cache.lock(resource, 10000, true).then((lock) => {
172
+ secondLockAcquired = true;
173
+ return lock;
174
+ });
175
+
176
+ // Advance time to trigger retry, but lock still held
177
+ await clock.tickAsync(CacheInstance.LOCK_RETRY_DELAY_MS);
178
+ expect(secondLockAcquired).to.be.false;
179
+ expect(hasSpy.callCount).to.be.greaterThan(hasCallsAfterFirstLock);
180
+
181
+ // Release first lock
182
+ await cache.unlock(firstLock);
183
+
184
+ // Advance time for next retry - should acquire now
185
+ await clock.tickAsync(CacheInstance.LOCK_RETRY_DELAY_MS);
186
+ const secondLock = await lockPromise;
187
+
188
+ expect(secondLockAcquired).to.be.true;
189
+ expect(secondLock).to.have.property('value');
190
+
191
+ hasSpy.restore();
192
+ await cache.unlock(secondLock);
193
+ } finally {
194
+ clock.restore();
195
+ }
196
+ });
197
+
198
+ it('with retry = false, throws immediately if lock is held', async () => {
199
+ const cache = new LocalCache();
200
+ const resource = `test-resource-${Math.random()}`;
201
+
202
+ const firstLock = await cache.lock(resource, 10000);
203
+ expect(await cache.hasLock(resource)).to.be.true;
204
+
205
+ let error: Error | undefined;
206
+ try {
207
+ await cache.lock(resource, 10000, false);
208
+ } catch (err) {
209
+ error = err as Error;
210
+ }
211
+
212
+ expect(error).to.exist;
213
+ expect(error!.message).to.include('Failed to acquire lock');
214
+ expect(error!.message).to.include('after 1 attempts');
215
+
216
+ await cache.unlock(firstLock);
217
+ });
218
+ });
118
219
  });
119
220
 
120
221
  function sleep(ms: number): Promise<void> {