@maestro-js/cache 1.0.0-alpha.0 → 1.0.0-alpha.10

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.
Files changed (2) hide show
  1. package/dist/index.js +47 -27
  2. package/package.json +8 -5
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 ?? Log.create();
13
+ const logger = loggerInput;
16
14
  const redis = new MockRedis();
17
- const lockEmitter = new EventEmitter();
18
- const channelPrefix = [keyPrefix, "maestro.events."].join("");
19
- const cacheLockChannelName = `${channelPrefix}cache-locks`;
20
- redis.on("error", (error) => {
21
- logger.error(error);
22
- });
23
- redis.on("message", (channel, message) => {
24
- if (channel === cacheLockChannelName) {
25
- lockEmitter.emit(message);
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
- lockEmitter.off(id, onRelease);
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
- lockEmitter.on(id, onRelease);
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
- lockEmitter.emit(id);
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
- lockEmitter.emit(id);
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 EventEmitter2 from "events";
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 ?? Log2.create();
187
+ const logger = loggerInput;
181
188
  const redis = new Redis2(port, url, {
182
189
  connectTimeout,
183
190
  keyPrefix
184
191
  });
185
- const lockEmitter = new EventEmitter2();
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.info("connected!");
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.error(error);
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
- redis.on("message", (channel, message) => {
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
@@ -11,15 +11,18 @@
11
11
  "dependencies": {
12
12
  "ioredis": "^5.4.1",
13
13
  "ioredis-timeout": "^1.5.0",
14
- "@maestro-js/log": "1.0.0-alpha.0",
15
- "@maestro-js/service-registry": "1.0.0-alpha.0"
14
+ "ioredis-mock": "^8.2.0",
15
+ "@types/ioredis-mock": "^8.2.6",
16
+ "@maestro-js/service-registry": "1.0.0-alpha.10"
17
+ },
18
+ "peerDependencies": {
19
+ "@maestro-js/log": "1.0.0-alpha.10"
16
20
  },
17
21
  "devDependencies": {
18
- "@types/ioredis-mock": "^8.2.6",
19
22
  "@types/node": "^22.19.11",
20
- "ioredis-mock": "^8.2.0"
23
+ "@maestro-js/log": "1.0.0-alpha.10"
21
24
  },
22
- "version": "1.0.0-alpha.0",
25
+ "version": "1.0.0-alpha.10",
23
26
  "publishConfig": {
24
27
  "access": "restricted"
25
28
  },