@zintrust/queue-redis 0.5.8 → 0.7.2
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/BullMQRedisQueue.js +19 -12
- package/dist/HttpQueueDriver.js +9 -5
- package/dist/RedisQueue.d.ts +10 -0
- package/dist/RedisQueue.js +92 -0
- package/dist/build-manifest.json +24 -12
- package/package.json +2 -2
package/dist/BullMQRedisQueue.js
CHANGED
|
@@ -315,6 +315,12 @@ export const BullMQRedisQueue = (() => {
|
|
|
315
315
|
},
|
|
316
316
|
};
|
|
317
317
|
};
|
|
318
|
+
const handleReleaseAfter = (payload, deduplicationId, releaseAfter, uniqueId) => {
|
|
319
|
+
if (releaseAfter !== undefined && releaseAfter !== null && typeof releaseAfter !== 'number') {
|
|
320
|
+
return attachWorkerSideReleaseMeta(payload, deduplicationId, releaseAfter, uniqueId);
|
|
321
|
+
}
|
|
322
|
+
return payload;
|
|
323
|
+
};
|
|
318
324
|
const handleDeduplication = async (payloadData, jobOptions, queue) => {
|
|
319
325
|
const deduplicationId = validateDeduplicationId(payloadData.deduplication);
|
|
320
326
|
if (!deduplicationId) {
|
|
@@ -330,32 +336,33 @@ export const BullMQRedisQueue = (() => {
|
|
|
330
336
|
? deduplication.ttl
|
|
331
337
|
: undefined;
|
|
332
338
|
const replace = deduplication.replace === true;
|
|
339
|
+
const collisionBehavior = deduplication.collisionBehavior === 'enqueue' ? 'enqueue' : 'suppress';
|
|
333
340
|
const jobId = jobOptions.jobId ?? generateUuid();
|
|
334
341
|
jobOptions.jobId = jobId;
|
|
335
342
|
// Check existing lock
|
|
336
343
|
const hasExistingLock = await checkExistingLock(scopedDeduplicationKey, deduplicationId, provider, replace, queue, jobId);
|
|
337
|
-
if (hasExistingLock) {
|
|
344
|
+
if (hasExistingLock && collisionBehavior === 'suppress') {
|
|
338
345
|
return { payloadToSend: payloadData, shouldReturn: true, returnValue: deduplicationId };
|
|
339
346
|
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
347
|
+
let lockAcquired = false;
|
|
348
|
+
if (!hasExistingLock) {
|
|
349
|
+
// Acquire lock
|
|
350
|
+
lockAcquired = await acquireDeduplicationLock(scopedDeduplicationKey, deduplicationId, provider, ttl, queue, jobId);
|
|
351
|
+
if (!lockAcquired && collisionBehavior === 'suppress') {
|
|
352
|
+
return { payloadToSend: payloadData, shouldReturn: true, returnValue: deduplicationId };
|
|
353
|
+
}
|
|
344
354
|
}
|
|
345
355
|
// Keep jobs for deduplication tracking
|
|
346
356
|
jobOptions.removeOnFail = 0;
|
|
347
357
|
jobOptions.removeOnComplete = 0;
|
|
348
358
|
let payloadToSend = payloadData;
|
|
349
359
|
// Handle releaseAfter numeric
|
|
350
|
-
if (
|
|
360
|
+
if (lockAcquired &&
|
|
361
|
+
typeof deduplication.releaseAfter === 'number' &&
|
|
362
|
+
deduplication.releaseAfter > 0) {
|
|
351
363
|
scheduleLockRelease(scopedDeduplicationKey, provider, ttl, deduplication.releaseAfter);
|
|
352
364
|
}
|
|
353
|
-
|
|
354
|
-
if (deduplication.releaseAfter !== undefined &&
|
|
355
|
-
deduplication.releaseAfter !== null &&
|
|
356
|
-
typeof deduplication.releaseAfter !== 'number') {
|
|
357
|
-
payloadToSend = attachWorkerSideReleaseMeta(payloadToSend, deduplicationId, deduplication.releaseAfter, payloadData.uniqueId);
|
|
358
|
-
}
|
|
365
|
+
payloadToSend = handleReleaseAfter(payloadToSend, deduplicationId, deduplication.releaseAfter, payloadData.uniqueId);
|
|
359
366
|
return { payloadToSend, shouldReturn: false };
|
|
360
367
|
};
|
|
361
368
|
return {
|
package/dist/HttpQueueDriver.js
CHANGED
|
@@ -216,9 +216,11 @@ export const HttpQueueDriver = Object.freeze({
|
|
|
216
216
|
}
|
|
217
217
|
catch (error) {
|
|
218
218
|
Logger.warn('HTTP queue enqueue failed; storing tracker fallback in memory', {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
219
|
+
...Logger.withTraceSkipContext({
|
|
220
|
+
queue,
|
|
221
|
+
fallbackJobId,
|
|
222
|
+
error: error instanceof Error ? error.message : String(error),
|
|
223
|
+
}),
|
|
222
224
|
});
|
|
223
225
|
await markPendingRecoveryFallback({
|
|
224
226
|
queue,
|
|
@@ -227,8 +229,10 @@ export const HttpQueueDriver = Object.freeze({
|
|
|
227
229
|
error,
|
|
228
230
|
});
|
|
229
231
|
Logger.warn('Job marked pending recovery in tracker', {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
+
...Logger.withTraceSkipContext({
|
|
233
|
+
queue,
|
|
234
|
+
jobId: fallbackJobId,
|
|
235
|
+
}),
|
|
232
236
|
});
|
|
233
237
|
return fallbackJobId;
|
|
234
238
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { QueueMessage } from '@zintrust/core';
|
|
2
|
+
interface IQueueDriver {
|
|
3
|
+
enqueue<T = unknown>(queue: string, payload: T): Promise<string>;
|
|
4
|
+
dequeue<T = unknown>(queue: string): Promise<QueueMessage<T> | undefined>;
|
|
5
|
+
ack(queue: string, id: string): Promise<void>;
|
|
6
|
+
length(queue: string): Promise<number>;
|
|
7
|
+
drain(queue: string): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export declare const RedisQueue: IQueueDriver;
|
|
10
|
+
export default RedisQueue;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { ErrorFactory, generateUuid, getRedisUrl, Logger } from '@zintrust/core';
|
|
2
|
+
export const RedisQueue = (() => {
|
|
3
|
+
let client = null;
|
|
4
|
+
let connected = false;
|
|
5
|
+
const ensureClient = async () => {
|
|
6
|
+
if (connected && client !== null)
|
|
7
|
+
return client;
|
|
8
|
+
const url = getRedisUrl();
|
|
9
|
+
if (url === null)
|
|
10
|
+
throw ErrorFactory.createConfigError('Redis queue driver requires REDIS_URL');
|
|
11
|
+
// Import lazily so package is optional for environments that don't use Redis
|
|
12
|
+
try {
|
|
13
|
+
// Prefer the redis package when available
|
|
14
|
+
try {
|
|
15
|
+
const mod = (await import('redis'));
|
|
16
|
+
const createClient = mod.createClient;
|
|
17
|
+
client = createClient({ url });
|
|
18
|
+
if (typeof client.connect === 'function') {
|
|
19
|
+
try {
|
|
20
|
+
await client.connect();
|
|
21
|
+
connected = true;
|
|
22
|
+
}
|
|
23
|
+
catch (connectionError) {
|
|
24
|
+
connected = false;
|
|
25
|
+
Logger.warn('Redis client connect failed:', String(connectionError));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
connected = true;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Fallback to ioredis when available (used by queue-monitor)
|
|
34
|
+
const mod = (await import('ioredis'));
|
|
35
|
+
const redis = mod.default(url);
|
|
36
|
+
client = {
|
|
37
|
+
rPush: (queue, value) => redis.rpush(queue, value),
|
|
38
|
+
lPop: (queue) => redis.lpop(queue),
|
|
39
|
+
lLen: (queue) => redis.llen(queue),
|
|
40
|
+
del: (queue) => redis.del(queue),
|
|
41
|
+
};
|
|
42
|
+
connected = true;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
const globalFake = globalThis
|
|
47
|
+
.__fakeRedisClient;
|
|
48
|
+
if (globalFake === undefined) {
|
|
49
|
+
throw ErrorFactory.createConfigError("Redis queue driver requires the 'redis' or 'ioredis' package (run `zin add queue:redis` / `zin plugin install queue:redis`, or `npm install redis` / `npm install ioredis`) or a test fake client set in globalThis.__fakeRedisClient", error);
|
|
50
|
+
}
|
|
51
|
+
client = globalFake;
|
|
52
|
+
connected = true;
|
|
53
|
+
}
|
|
54
|
+
if (client === null)
|
|
55
|
+
throw ErrorFactory.createConfigError('Redis client could not be initialized');
|
|
56
|
+
return client;
|
|
57
|
+
};
|
|
58
|
+
return {
|
|
59
|
+
async enqueue(queue, payload) {
|
|
60
|
+
const cli = await ensureClient();
|
|
61
|
+
const id = generateUuid();
|
|
62
|
+
const msg = JSON.stringify({ id, payload, attempts: 0 });
|
|
63
|
+
await cli.rPush(queue, msg);
|
|
64
|
+
return id;
|
|
65
|
+
},
|
|
66
|
+
async dequeue(queue) {
|
|
67
|
+
const cli = await ensureClient();
|
|
68
|
+
const raw = await cli.lPop(queue);
|
|
69
|
+
if (raw === null)
|
|
70
|
+
return undefined;
|
|
71
|
+
try {
|
|
72
|
+
const parsed = JSON.parse(raw);
|
|
73
|
+
return parsed;
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
throw ErrorFactory.createTryCatchError('Failed to parse queue message', err);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
async ack(_queue, _id) {
|
|
80
|
+
return Promise.resolve(); // NOSONAR
|
|
81
|
+
},
|
|
82
|
+
async length(queue) {
|
|
83
|
+
const cli = await ensureClient();
|
|
84
|
+
return cli.lLen(queue);
|
|
85
|
+
},
|
|
86
|
+
async drain(queue) {
|
|
87
|
+
const cli = await ensureClient();
|
|
88
|
+
await cli.del(queue);
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
})();
|
|
92
|
+
export default RedisQueue;
|
package/dist/build-manifest.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zintrust/queue-redis",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"buildDate": "2026-04-
|
|
3
|
+
"version": "0.7.2",
|
|
4
|
+
"buildDate": "2026-04-18T19:23:21.152Z",
|
|
5
5
|
"buildEnvironment": {
|
|
6
|
-
"node": "
|
|
7
|
-
"platform": "
|
|
8
|
-
"arch": "
|
|
6
|
+
"node": "v22.22.1",
|
|
7
|
+
"platform": "darwin",
|
|
8
|
+
"arch": "arm64"
|
|
9
9
|
},
|
|
10
10
|
"git": {
|
|
11
|
-
"commit": "
|
|
12
|
-
"branch": "
|
|
11
|
+
"commit": "126e1196",
|
|
12
|
+
"branch": "release"
|
|
13
13
|
},
|
|
14
14
|
"package": {
|
|
15
15
|
"engines": {
|
|
@@ -29,16 +29,16 @@
|
|
|
29
29
|
"sha256": "52fb0f688cd17cc7d8e8128e60df6f5eea4c803282382ac75550e6aacee7cbb0"
|
|
30
30
|
},
|
|
31
31
|
"BullMQRedisQueue.js": {
|
|
32
|
-
"size":
|
|
33
|
-
"sha256": "
|
|
32
|
+
"size": 21981,
|
|
33
|
+
"sha256": "b72bda67ed62205f419775dc89373e4c20023fb2f92fa99faa6bfebb853f5635"
|
|
34
34
|
},
|
|
35
35
|
"HttpQueueDriver.d.ts": {
|
|
36
36
|
"size": 835,
|
|
37
37
|
"sha256": "31735e10a83cf905ca48f3bf1c79f40029b9ac7c0ce6c26751ad646fa77bc764"
|
|
38
38
|
},
|
|
39
39
|
"HttpQueueDriver.js": {
|
|
40
|
-
"size":
|
|
41
|
-
"sha256": "
|
|
40
|
+
"size": 9116,
|
|
41
|
+
"sha256": "28f10537bf9520772d8546c956fdaa7d3c489abd5be38ca78ee4eca41d8c9907"
|
|
42
42
|
},
|
|
43
43
|
"QueueHttpGateway.d.ts": {
|
|
44
44
|
"size": 432,
|
|
@@ -56,13 +56,25 @@
|
|
|
56
56
|
"size": 5464,
|
|
57
57
|
"sha256": "18b785c47b4df689f9969625880d1b559e6cf8c95bb8c3cd3a4112fa75e0d870"
|
|
58
58
|
},
|
|
59
|
+
"RedisQueue.d.ts": {
|
|
60
|
+
"size": 438,
|
|
61
|
+
"sha256": "eefad366ae71d63044b23038265bf3eb60a0277e41ac70f57c5973d79f2af5ce"
|
|
62
|
+
},
|
|
63
|
+
"RedisQueue.js": {
|
|
64
|
+
"size": 3593,
|
|
65
|
+
"sha256": "dc8b2c28b2e288e048423067f90ffbe0389ac813086246a1c8fafeeeab5c142d"
|
|
66
|
+
},
|
|
67
|
+
"build-manifest.json": {
|
|
68
|
+
"size": 2512,
|
|
69
|
+
"sha256": "95ec4ea44d0088301c629fce69e4960e0541969592bf5b1eafbbc9fe8424da5f"
|
|
70
|
+
},
|
|
59
71
|
"index.d.ts": {
|
|
60
72
|
"size": 565,
|
|
61
73
|
"sha256": "7bc063419989a39530b3a4213627e0aea33fbaacac8c307d9e7e654c99bd5b8d"
|
|
62
74
|
},
|
|
63
75
|
"index.js": {
|
|
64
76
|
"size": 676,
|
|
65
|
-
"sha256": "
|
|
77
|
+
"sha256": "a46d4365952581f0d5df7eb9e97d6ca54128ca891a18195c761bf49f7f0a06da"
|
|
66
78
|
},
|
|
67
79
|
"register.d.ts": {
|
|
68
80
|
"size": 170,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zintrust/queue-redis",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.2",
|
|
4
4
|
"description": "Redis queue driver for ZinTrust.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"node": ">=20.0.0"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"@zintrust/core": "^0.
|
|
26
|
+
"@zintrust/core": "^0.7.2"
|
|
27
27
|
},
|
|
28
28
|
"publishConfig": {
|
|
29
29
|
"access": "public"
|