@maestro-js/cache 1.0.0-alpha.2 → 1.0.0-alpha.21
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/index.d.ts +4 -3
- package/dist/index.js +47 -27
- package/package.json +7 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { Log } from '@maestro-js/log';
|
|
2
2
|
import Redis$1, { Redis } from 'ioredis';
|
|
3
3
|
|
|
4
|
-
type DurationString = `${number} ${'day' | 'days' | 'hour' | 'hours' | 'minute' | 'minutes' | 'second' | 'seconds'}`;
|
|
5
|
-
|
|
6
4
|
/** Contract that every cache backend (Redis, MockRedis, etc.) must implement */
|
|
7
5
|
interface CacheDriver {
|
|
8
6
|
/** Checks whether `key` exists in the store */
|
|
@@ -62,6 +60,9 @@ declare function redisCacheDriver({ url, port, operationTimeout, connectTimeout,
|
|
|
62
60
|
connection: Redis$1;
|
|
63
61
|
};
|
|
64
62
|
|
|
63
|
+
type DurationString = `${number} ${'day' | 'days' | 'hour' | 'hours' | 'minute' | 'minutes' | 'second' | 'seconds'}`;
|
|
64
|
+
|
|
65
|
+
type CacheDurationString = DurationString;
|
|
65
66
|
/**
|
|
66
67
|
* Creates a new Cache service instance with the provided driver configuration.
|
|
67
68
|
*/
|
|
@@ -163,7 +164,7 @@ declare namespace Cache {
|
|
|
163
164
|
/** Pluggable backend implementation — see `Cache.drivers` for built-in options */
|
|
164
165
|
type Driver = CacheDriver;
|
|
165
166
|
/** Duration string like `'5 minutes'` or `'1 hour'` */
|
|
166
|
-
type DurationString =
|
|
167
|
+
type DurationString = CacheDurationString;
|
|
167
168
|
/** TTL options for `remember` — a number (seconds), `null` (forever), a duration string, or an object with `ttl` and `swr` */
|
|
168
169
|
type RememberOptions = number | null | DurationString | {
|
|
169
170
|
ttl: number | DurationString | null;
|
package/dist/index.js
CHANGED
|
@@ -3,27 +3,37 @@ import assert from "assert";
|
|
|
3
3
|
import { ServiceRegistry } from "@maestro-js/service-registry";
|
|
4
4
|
|
|
5
5
|
// src/mock-redis-cache-driver.ts
|
|
6
|
-
import EventEmitter from "events";
|
|
7
6
|
import { randomUUID } from "crypto";
|
|
8
|
-
import { Log } from "@maestro-js/log";
|
|
9
7
|
import MockRedis from "ioredis-mock";
|
|
10
8
|
import "ioredis";
|
|
11
9
|
function mockRedisCacheDriver({
|
|
12
10
|
logger: loggerInput,
|
|
13
11
|
keyPrefix = ""
|
|
14
12
|
}) {
|
|
15
|
-
const logger = loggerInput
|
|
13
|
+
const logger = loggerInput;
|
|
16
14
|
const redis = new MockRedis();
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
15
|
+
const lockWaiters = /* @__PURE__ */ new Map();
|
|
16
|
+
function addWaiter(lockId, callback) {
|
|
17
|
+
const queue = lockWaiters.get(lockId) ?? [];
|
|
18
|
+
queue.push(callback);
|
|
19
|
+
lockWaiters.set(lockId, queue);
|
|
20
|
+
}
|
|
21
|
+
function removeWaiter(lockId, callback) {
|
|
22
|
+
const queue = lockWaiters.get(lockId);
|
|
23
|
+
if (queue) {
|
|
24
|
+
const index = queue.indexOf(callback);
|
|
25
|
+
if (index >= 0) queue.splice(index, 1);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function notifyNextWaiter(lockId) {
|
|
29
|
+
const queue = lockWaiters.get(lockId);
|
|
30
|
+
if (queue && queue.length > 0) {
|
|
31
|
+
const next = queue.shift();
|
|
32
|
+
next();
|
|
26
33
|
}
|
|
34
|
+
}
|
|
35
|
+
redis.on("error", (error) => {
|
|
36
|
+
logger?.error(error);
|
|
27
37
|
});
|
|
28
38
|
return {
|
|
29
39
|
async has(key) {
|
|
@@ -105,7 +115,7 @@ function mockRedisCacheDriver({
|
|
|
105
115
|
let waitingForAcquire = false;
|
|
106
116
|
const cleanup = () => {
|
|
107
117
|
settled = true;
|
|
108
|
-
|
|
118
|
+
removeWaiter(id, onRelease);
|
|
109
119
|
clearInterval(fallbackPoll);
|
|
110
120
|
};
|
|
111
121
|
const timeout = setTimeout(() => {
|
|
@@ -117,7 +127,7 @@ function mockRedisCacheDriver({
|
|
|
117
127
|
reject(new Error(`Could not acquire lock: ${name}`));
|
|
118
128
|
}, seconds * 1e3);
|
|
119
129
|
const onRelease = async () => {
|
|
120
|
-
if (settled) return;
|
|
130
|
+
if (settled || acquiring) return;
|
|
121
131
|
acquiring = true;
|
|
122
132
|
const acquired = await tryLock();
|
|
123
133
|
acquiring = false;
|
|
@@ -132,7 +142,7 @@ function mockRedisCacheDriver({
|
|
|
132
142
|
reject(new Error(`Could not acquire lock: ${name}`));
|
|
133
143
|
}
|
|
134
144
|
};
|
|
135
|
-
|
|
145
|
+
addWaiter(id, onRelease);
|
|
136
146
|
const fallbackPoll = setInterval(onRelease, 250);
|
|
137
147
|
onRelease();
|
|
138
148
|
});
|
|
@@ -149,14 +159,12 @@ function mockRedisCacheDriver({
|
|
|
149
159
|
callId
|
|
150
160
|
);
|
|
151
161
|
if (released === 1) {
|
|
152
|
-
|
|
153
|
-
await redis.publish(cacheLockChannelName, id);
|
|
162
|
+
notifyNextWaiter(id);
|
|
154
163
|
}
|
|
155
164
|
}
|
|
156
165
|
async function forceRelease() {
|
|
157
166
|
await redis.del(id);
|
|
158
|
-
|
|
159
|
-
await redis.publish(cacheLockChannelName, id);
|
|
167
|
+
notifyNextWaiter(id);
|
|
160
168
|
}
|
|
161
169
|
return { get, release, forceRelease, isAvailable, block };
|
|
162
170
|
}
|
|
@@ -164,11 +172,10 @@ function mockRedisCacheDriver({
|
|
|
164
172
|
}
|
|
165
173
|
|
|
166
174
|
// src/redis-cache-driver.ts
|
|
167
|
-
import
|
|
175
|
+
import EventEmitter from "events";
|
|
168
176
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
169
177
|
import Redis2 from "ioredis";
|
|
170
178
|
import RedisTimeout from "ioredis-timeout";
|
|
171
|
-
import { Log as Log2 } from "@maestro-js/log";
|
|
172
179
|
function redisCacheDriver({
|
|
173
180
|
url,
|
|
174
181
|
port,
|
|
@@ -177,26 +184,39 @@ function redisCacheDriver({
|
|
|
177
184
|
keyPrefix = "",
|
|
178
185
|
logger: loggerInput
|
|
179
186
|
}) {
|
|
180
|
-
const logger = loggerInput
|
|
187
|
+
const logger = loggerInput;
|
|
181
188
|
const redis = new Redis2(port, url, {
|
|
182
189
|
connectTimeout,
|
|
183
190
|
keyPrefix
|
|
184
191
|
});
|
|
185
|
-
const
|
|
192
|
+
const subscriber = new Redis2(port, url, {
|
|
193
|
+
connectTimeout,
|
|
194
|
+
keyPrefix
|
|
195
|
+
});
|
|
196
|
+
const lockEmitter = new EventEmitter();
|
|
186
197
|
const channelPrefix = [keyPrefix, "maestro.events."].join("");
|
|
187
198
|
const cacheLockChannelName = `${channelPrefix}cache-locks`;
|
|
188
199
|
redis.on("connect", () => {
|
|
189
|
-
logger
|
|
200
|
+
logger?.info("connected!");
|
|
190
201
|
RedisTimeout.timeout("set", operationTimeout, redis);
|
|
191
202
|
RedisTimeout.timeout("get", operationTimeout, redis);
|
|
192
203
|
RedisTimeout.timeout("exists", operationTimeout, redis);
|
|
193
204
|
RedisTimeout.timeout("del", operationTimeout, redis);
|
|
194
205
|
RedisTimeout.timeout("publish", operationTimeout, redis);
|
|
206
|
+
RedisTimeout.timeout("eval", operationTimeout, redis);
|
|
195
207
|
});
|
|
196
208
|
redis.on("error", (error) => {
|
|
197
|
-
logger
|
|
209
|
+
logger?.error(error);
|
|
210
|
+
});
|
|
211
|
+
subscriber.on("connect", () => {
|
|
212
|
+
subscriber.subscribe(cacheLockChannelName).catch((err) => {
|
|
213
|
+
logger?.error(`Failed to subscribe to ${cacheLockChannelName}: %s`, err.message);
|
|
214
|
+
});
|
|
215
|
+
});
|
|
216
|
+
subscriber.on("error", (error) => {
|
|
217
|
+
logger?.error(error);
|
|
198
218
|
});
|
|
199
|
-
|
|
219
|
+
subscriber.on("message", (channel, message) => {
|
|
200
220
|
if (channel === cacheLockChannelName) {
|
|
201
221
|
lockEmitter.emit(message);
|
|
202
222
|
}
|
|
@@ -293,7 +313,7 @@ function redisCacheDriver({
|
|
|
293
313
|
reject(new Error(`Could not acquire lock: ${name}`));
|
|
294
314
|
}, seconds * 1e3);
|
|
295
315
|
const onRelease = async () => {
|
|
296
|
-
if (settled) return;
|
|
316
|
+
if (settled || acquiring) return;
|
|
297
317
|
acquiring = true;
|
|
298
318
|
const acquired = await tryLock();
|
|
299
319
|
acquiring = false;
|
package/package.json
CHANGED
|
@@ -13,13 +13,16 @@
|
|
|
13
13
|
"ioredis-timeout": "^1.5.0",
|
|
14
14
|
"ioredis-mock": "^8.2.0",
|
|
15
15
|
"@types/ioredis-mock": "^8.2.6",
|
|
16
|
-
"@maestro-js/
|
|
17
|
-
|
|
16
|
+
"@maestro-js/service-registry": "1.0.0-alpha.21"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"@maestro-js/log": "1.0.0-alpha.21"
|
|
18
20
|
},
|
|
19
21
|
"devDependencies": {
|
|
20
|
-
"@types/node": "^22.19.11"
|
|
22
|
+
"@types/node": "^22.19.11",
|
|
23
|
+
"@maestro-js/log": "1.0.0-alpha.21"
|
|
21
24
|
},
|
|
22
|
-
"version": "1.0.0-alpha.
|
|
25
|
+
"version": "1.0.0-alpha.21",
|
|
23
26
|
"publishConfig": {
|
|
24
27
|
"access": "restricted"
|
|
25
28
|
},
|