@zintrust/queue-redis 0.4.70 → 0.4.74

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,4 +1,4 @@
1
- import { Cloudflare, createLockProvider, createRedisConnection, Env, ErrorFactory, generateUuid, getBullMQSafeQueueName, getLockProvider, Logger, queueConfig, registerLockProvider, resolveLockPrefix, ZintrustLang, } from '@zintrust/core';
1
+ import { Cloudflare, createLockProvider, createRedisConnection, Env, ErrorFactory, generateUuid, getBullMQSafeQueueName, getLockProvider, Logger, queueConfig, registerLockProvider, resolveDeduplicationLockKey, resolveLockPrefix, ZintrustLang, } from '@zintrust/core';
2
2
  import { Queue } from 'bullmq';
3
3
  import { HttpQueueDriver } from './HttpQueueDriver.js';
4
4
  export const shouldUseHttpProxyDriver = () => {
@@ -264,8 +264,8 @@ export const BullMQRedisQueue = (() => {
264
264
  const deduplicationId = String(deduplication.id).trim();
265
265
  return deduplicationId.length > 0 ? deduplicationId : null;
266
266
  };
267
- const checkExistingLock = async (deduplicationId, provider, replace, queue, jobId) => {
268
- const status = await provider.status(deduplicationId);
267
+ const checkExistingLock = async (scopedDeduplicationKey, deduplicationId, provider, replace, queue, jobId) => {
268
+ const status = await provider.status(scopedDeduplicationKey);
269
269
  if (status.exists && !replace) {
270
270
  Logger.info('BullMQ: Job deduplicated', {
271
271
  queue,
@@ -276,9 +276,9 @@ export const BullMQRedisQueue = (() => {
276
276
  }
277
277
  return false;
278
278
  };
279
- const acquireDeduplicationLock = async (deduplicationId, provider, ttl, queue, jobId) => {
279
+ const acquireDeduplicationLock = async (scopedDeduplicationKey, deduplicationId, provider, ttl, queue, jobId) => {
280
280
  const lockOptions = ttl ? { ttl } : {};
281
- const lock = await provider.acquire(deduplicationId, lockOptions);
281
+ const lock = await provider.acquire(scopedDeduplicationKey, lockOptions);
282
282
  if (!lock.acquired) {
283
283
  Logger.info('BullMQ: Job deduplicated (lock collision)', {
284
284
  queue,
@@ -294,10 +294,10 @@ export const BullMQRedisQueue = (() => {
294
294
  });
295
295
  return true;
296
296
  };
297
- const scheduleLockRelease = (deduplicationId, provider, ttl, releaseAfter) => {
297
+ const scheduleLockRelease = (scopedDeduplicationKey, provider, ttl, releaseAfter) => {
298
298
  const timeoutId = globalThis.setTimeout(() => {
299
299
  provider.release({
300
- key: deduplicationId,
300
+ key: scopedDeduplicationKey,
301
301
  ttl: ttl ?? 0,
302
302
  acquired: true,
303
303
  expires: new Date(Date.now() + (ttl ?? 0)),
@@ -325,6 +325,7 @@ export const BullMQRedisQueue = (() => {
325
325
  return { payloadToSend: payloadData, shouldReturn: false };
326
326
  }
327
327
  const provider = getLockProviderForQueue(payloadData.uniqueVia);
328
+ const scopedDeduplicationKey = resolveDeduplicationLockKey(queue, deduplicationId);
328
329
  const ttl = typeof deduplication.ttl === 'number' && deduplication.ttl > 0
329
330
  ? deduplication.ttl
330
331
  : undefined;
@@ -332,12 +333,12 @@ export const BullMQRedisQueue = (() => {
332
333
  const jobId = jobOptions.jobId ?? generateUuid();
333
334
  jobOptions.jobId = jobId;
334
335
  // Check existing lock
335
- const hasExistingLock = await checkExistingLock(deduplicationId, provider, replace, queue, jobId);
336
+ const hasExistingLock = await checkExistingLock(scopedDeduplicationKey, deduplicationId, provider, replace, queue, jobId);
336
337
  if (hasExistingLock) {
337
338
  return { payloadToSend: payloadData, shouldReturn: true, returnValue: deduplicationId };
338
339
  }
339
340
  // Acquire lock
340
- const lockAcquired = await acquireDeduplicationLock(deduplicationId, provider, ttl, queue, jobId);
341
+ const lockAcquired = await acquireDeduplicationLock(scopedDeduplicationKey, deduplicationId, provider, ttl, queue, jobId);
341
342
  if (!lockAcquired) {
342
343
  return { payloadToSend: payloadData, shouldReturn: true, returnValue: deduplicationId };
343
344
  }
@@ -347,7 +348,7 @@ export const BullMQRedisQueue = (() => {
347
348
  let payloadToSend = payloadData;
348
349
  // Handle releaseAfter numeric
349
350
  if (typeof deduplication.releaseAfter === 'number' && deduplication.releaseAfter > 0) {
350
- scheduleLockRelease(deduplicationId, provider, ttl, deduplication.releaseAfter);
351
+ scheduleLockRelease(scopedDeduplicationKey, provider, ttl, deduplication.releaseAfter);
351
352
  }
352
353
  // Handle releaseAfter non-numeric
353
354
  if (deduplication.releaseAfter !== undefined &&
@@ -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;
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "@zintrust/queue-redis",
3
- "version": "0.4.70",
4
- "buildDate": "2026-04-06T16:10:45.630Z",
3
+ "version": "0.4.74",
4
+ "buildDate": "2026-04-07T11:00:15.411Z",
5
5
  "buildEnvironment": {
6
- "node": "v20.20.2",
7
- "platform": "linux",
8
- "arch": "x64"
6
+ "node": "v22.22.1",
7
+ "platform": "darwin",
8
+ "arch": "arm64"
9
9
  },
10
10
  "git": {
11
- "commit": "b92b2b05",
12
- "branch": "master"
11
+ "commit": "9bdfc570",
12
+ "branch": "release"
13
13
  },
14
14
  "package": {
15
15
  "engines": {
@@ -29,8 +29,8 @@
29
29
  "sha256": "52fb0f688cd17cc7d8e8128e60df6f5eea4c803282382ac75550e6aacee7cbb0"
30
30
  },
31
31
  "BullMQRedisQueue.js": {
32
- "size": 21327,
33
- "sha256": "a35f9d822a3166d57ca48ea1f4894e9fe7996fb842c2f8eeb5cd8be4de866a6a"
32
+ "size": 21579,
33
+ "sha256": "042803997f2f9895827ce34359bb62c80b2b889ab4ddc9cbbe191924a376684a"
34
34
  },
35
35
  "HttpQueueDriver.d.ts": {
36
36
  "size": 835,
@@ -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": 2513,
69
+ "sha256": "640dd3671f0f79dedc8ec4432ccf15cfdd351793c2a379cbda83d6a61bd424e3"
70
+ },
59
71
  "index.d.ts": {
60
72
  "size": 565,
61
73
  "sha256": "7bc063419989a39530b3a4213627e0aea33fbaacac8c307d9e7e654c99bd5b8d"
62
74
  },
63
75
  "index.js": {
64
76
  "size": 677,
65
- "sha256": "6579dfb73bfcc427e23eb91a8c1791b714216e695dec1fd87f654c1ff7033684"
77
+ "sha256": "62b975ffe5348710c55e4a589ff35a54b992293b68f23479a33360f6f482b310"
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.4.70",
3
+ "version": "0.4.74",
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.4.70"
26
+ "@zintrust/core": "^0.4.74"
27
27
  },
28
28
  "publishConfig": {
29
29
  "access": "public"