@holo-js/queue-redis 0.1.3 → 0.1.5
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 +7 -2
- package/dist/index.mjs +58 -15
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -104,10 +104,14 @@ declare class RedisQueueDriver implements QueueAsyncDriver {
|
|
|
104
104
|
private readonly managedRedisConnection?;
|
|
105
105
|
private readonly queues;
|
|
106
106
|
private readonly workers;
|
|
107
|
+
private readonly workerReadyPromises;
|
|
107
108
|
private readonly reservations;
|
|
108
109
|
private queueCursor;
|
|
109
110
|
constructor(connection: NormalizedQueueRedisConnectionConfig, context: QueueDriverFactoryContext);
|
|
110
111
|
private getQueue;
|
|
112
|
+
private createWorkerKey;
|
|
113
|
+
private normalizeReserveBlockFor;
|
|
114
|
+
private resolveWorkerDrainDelay;
|
|
111
115
|
private getWorker;
|
|
112
116
|
private normalizeQueueNames;
|
|
113
117
|
private rotateQueueNames;
|
|
@@ -116,8 +120,9 @@ declare class RedisQueueDriver implements QueueAsyncDriver {
|
|
|
116
120
|
private settleReservation;
|
|
117
121
|
dispatch<TPayload extends QueueJsonValue = QueueJsonValue, TResult = unknown>(job: QueueJobEnvelope<TPayload>): Promise<QueueDriverDispatchResult<TResult>>;
|
|
118
122
|
reserve<TPayload extends QueueJsonValue = QueueJsonValue>(input: {
|
|
119
|
-
readonly queueNames
|
|
120
|
-
readonly workerId
|
|
123
|
+
readonly queueNames?: readonly string[];
|
|
124
|
+
readonly workerId?: string;
|
|
125
|
+
readonly timeout?: number;
|
|
121
126
|
}): Promise<QueueReservedJob<TPayload> | null>;
|
|
122
127
|
acknowledge(job: QueueReservedJob): Promise<void>;
|
|
123
128
|
release(job: QueueReservedJob, options?: QueueReleaseOptions): Promise<void>;
|
package/dist/index.mjs
CHANGED
|
@@ -140,6 +140,7 @@ var RedisQueueDriver = class {
|
|
|
140
140
|
managedRedisConnection;
|
|
141
141
|
queues = /* @__PURE__ */ new Map();
|
|
142
142
|
workers = /* @__PURE__ */ new Map();
|
|
143
|
+
workerReadyPromises = /* @__PURE__ */ new Map();
|
|
143
144
|
reservations = /* @__PURE__ */ new Map();
|
|
144
145
|
queueCursor = 0;
|
|
145
146
|
getQueue(queueName) {
|
|
@@ -157,10 +158,30 @@ var RedisQueueDriver = class {
|
|
|
157
158
|
this.queues.set(queueName, queue);
|
|
158
159
|
return queue;
|
|
159
160
|
}
|
|
160
|
-
|
|
161
|
-
|
|
161
|
+
createWorkerKey(queueName, blockFor) {
|
|
162
|
+
return `${queueName}:${blockFor}`;
|
|
163
|
+
}
|
|
164
|
+
normalizeReserveBlockFor(timeout) {
|
|
165
|
+
if (typeof timeout === "undefined") {
|
|
166
|
+
return this.connection.blockFor;
|
|
167
|
+
}
|
|
168
|
+
if (!Number.isFinite(timeout) || timeout < 0) {
|
|
169
|
+
throw new Error("[Holo Queue] Redis queue reservation timeout must be a non-negative finite number when provided.");
|
|
170
|
+
}
|
|
171
|
+
return timeout;
|
|
172
|
+
}
|
|
173
|
+
resolveWorkerDrainDelay(blockFor) {
|
|
174
|
+
return blockFor > 0 ? blockFor : 1;
|
|
175
|
+
}
|
|
176
|
+
async getWorker(queueName, blockFor = this.connection.blockFor) {
|
|
177
|
+
const workerKey = this.createWorkerKey(queueName, blockFor);
|
|
178
|
+
const pending = this.workerReadyPromises.get(workerKey);
|
|
179
|
+
if (pending) {
|
|
180
|
+
return (await pending).worker;
|
|
181
|
+
}
|
|
182
|
+
const cached = this.workers.get(workerKey);
|
|
162
183
|
if (cached) {
|
|
163
|
-
return cached;
|
|
184
|
+
return cached.worker;
|
|
164
185
|
}
|
|
165
186
|
const worker = new BullWorker(
|
|
166
187
|
queueName,
|
|
@@ -169,22 +190,40 @@ var RedisQueueDriver = class {
|
|
|
169
190
|
autorun: false,
|
|
170
191
|
concurrency: 1,
|
|
171
192
|
connection: this.bullConnection,
|
|
172
|
-
drainDelay: this.
|
|
193
|
+
drainDelay: this.resolveWorkerDrainDelay(blockFor),
|
|
173
194
|
lockDuration: this.connection.retryAfter * 1e3,
|
|
174
195
|
removeOnComplete: { count: 0 },
|
|
175
196
|
removeOnFail: { count: 0 }
|
|
176
197
|
}
|
|
177
198
|
);
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
199
|
+
const workerRecord = {
|
|
200
|
+
queueName,
|
|
201
|
+
worker
|
|
202
|
+
};
|
|
203
|
+
const ready = worker.waitUntilReady().then(() => workerRecord).catch(async (error) => {
|
|
204
|
+
if (this.workers.get(workerKey) === workerRecord) {
|
|
205
|
+
this.workers.delete(workerKey);
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
await worker.close(true);
|
|
209
|
+
} catch {
|
|
210
|
+
}
|
|
211
|
+
throw error;
|
|
212
|
+
}).finally(() => {
|
|
213
|
+
if (this.workerReadyPromises.get(workerKey) === ready) {
|
|
214
|
+
this.workerReadyPromises.delete(workerKey);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
this.workers.set(workerKey, workerRecord);
|
|
218
|
+
this.workerReadyPromises.set(workerKey, ready);
|
|
219
|
+
return (await ready).worker;
|
|
181
220
|
}
|
|
182
221
|
normalizeQueueNames(queueNames) {
|
|
183
222
|
if (!queueNames || queueNames.length === 0) {
|
|
184
223
|
return [.../* @__PURE__ */ new Set([
|
|
185
224
|
this.connection.queue,
|
|
186
225
|
...this.queues.keys(),
|
|
187
|
-
...this.workers.
|
|
226
|
+
...[...this.workers.values()].map((worker) => worker.queueName)
|
|
188
227
|
])];
|
|
189
228
|
}
|
|
190
229
|
return [...new Set(queueNames)];
|
|
@@ -242,9 +281,8 @@ var RedisQueueDriver = class {
|
|
|
242
281
|
await callback(reservation);
|
|
243
282
|
} catch (error) {
|
|
244
283
|
throw wrapRedisError(this.name, action, error);
|
|
245
|
-
} finally {
|
|
246
|
-
this.reservations.delete(reserved.reservationId);
|
|
247
284
|
}
|
|
285
|
+
this.reservations.delete(reserved.reservationId);
|
|
248
286
|
}
|
|
249
287
|
async dispatch(job) {
|
|
250
288
|
try {
|
|
@@ -268,8 +306,10 @@ var RedisQueueDriver = class {
|
|
|
268
306
|
async reserve(input) {
|
|
269
307
|
try {
|
|
270
308
|
const queueNames = this.rotateQueueNames(this.normalizeQueueNames(input.queueNames));
|
|
309
|
+
const workerId = input.workerId ?? this.name;
|
|
310
|
+
const blockFor = this.normalizeReserveBlockFor(input.timeout);
|
|
271
311
|
for (const queueName of queueNames) {
|
|
272
|
-
const token2 = `${
|
|
312
|
+
const token2 = `${workerId}:${randomUUID()}`;
|
|
273
313
|
const worker2 = await this.getWorker(queueName);
|
|
274
314
|
const job2 = await worker2.getNextJob(token2, { block: false });
|
|
275
315
|
if (job2) {
|
|
@@ -277,11 +317,11 @@ var RedisQueueDriver = class {
|
|
|
277
317
|
}
|
|
278
318
|
}
|
|
279
319
|
const [blockingQueue] = queueNames;
|
|
280
|
-
if (!blockingQueue ||
|
|
320
|
+
if (!blockingQueue || blockFor <= 0) {
|
|
281
321
|
return null;
|
|
282
322
|
}
|
|
283
|
-
const token = `${
|
|
284
|
-
const worker = await this.getWorker(blockingQueue);
|
|
323
|
+
const token = `${workerId}:${randomUUID()}`;
|
|
324
|
+
const worker = await this.getWorker(blockingQueue, blockFor);
|
|
285
325
|
const job = await worker.getNextJob(token, { block: true });
|
|
286
326
|
if (!job) {
|
|
287
327
|
return null;
|
|
@@ -327,10 +367,12 @@ var RedisQueueDriver = class {
|
|
|
327
367
|
}
|
|
328
368
|
async close() {
|
|
329
369
|
const resources = [
|
|
330
|
-
...this.workers.values(),
|
|
370
|
+
...[...this.workers.values()].map((worker) => worker.worker),
|
|
331
371
|
...this.queues.values()
|
|
332
372
|
];
|
|
373
|
+
const workerReadyPromises = [...this.workerReadyPromises.values()];
|
|
333
374
|
this.reservations.clear();
|
|
375
|
+
this.workerReadyPromises.clear();
|
|
334
376
|
this.workers.clear();
|
|
335
377
|
this.queues.clear();
|
|
336
378
|
let closeRejection;
|
|
@@ -342,6 +384,7 @@ var RedisQueueDriver = class {
|
|
|
342
384
|
}
|
|
343
385
|
await resource.close();
|
|
344
386
|
}));
|
|
387
|
+
await Promise.allSettled(workerReadyPromises);
|
|
345
388
|
closeRejection = results.find((result) => result.status === "rejected");
|
|
346
389
|
} finally {
|
|
347
390
|
if (this.managedRedisConnection) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@holo-js/queue-redis",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Holo-JS Framework - Redis queue driver",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,18 +23,18 @@
|
|
|
23
23
|
"test": "vitest --run"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"@holo-js/queue": "^0.1.
|
|
26
|
+
"@holo-js/queue": "^0.1.5"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"bullmq": "^5.71.0",
|
|
30
|
-
"ioredis": "
|
|
30
|
+
"ioredis": "^5.4.2",
|
|
31
31
|
"tslib": "^2.8.1"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@holo-js/queue": "
|
|
34
|
+
"@holo-js/queue": "^0.1.5",
|
|
35
35
|
"@types/node": "^22.10.2",
|
|
36
36
|
"tsup": "^8.3.5",
|
|
37
37
|
"typescript": "^5.7.2",
|
|
38
|
-
"vitest": "^
|
|
38
|
+
"vitest": "^4.1.5"
|
|
39
39
|
}
|
|
40
40
|
}
|