@zintrust/queue-redis 0.1.41 → 0.1.43

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.
@@ -343,11 +343,13 @@ export const BullMQRedisQueue = (() => {
343
343
  if (shouldUseHttpProxyDriver()) {
344
344
  return HttpQueueDriver.enqueue(queue, payload);
345
345
  }
346
+ let requestedJobId;
346
347
  try {
347
348
  const q = getQueue(queue);
348
349
  // Extract BullMQ options from payload with proper typing
349
350
  const payloadData = payload;
350
351
  const jobOptions = createJobOptions(payloadData);
352
+ requestedJobId = jobOptions.jobId;
351
353
  // Handle deduplication
352
354
  const deduplicationResult = await handleDeduplication(payloadData, jobOptions, queue);
353
355
  if (deduplicationResult.shouldReturn && deduplicationResult.returnValue) {
@@ -364,6 +366,14 @@ export const BullMQRedisQueue = (() => {
364
366
  return String(job.id);
365
367
  }
366
368
  catch (error) {
369
+ const message = error instanceof Error ? error.message : String(error);
370
+ // BullMQ throws when a job with the same jobId already exists.
371
+ // In enqueue-fallback/recovery paths we want strict idempotency: treat as success.
372
+ if (requestedJobId !== undefined &&
373
+ /jobid/i.test(message) &&
374
+ /already exists/i.test(message)) {
375
+ return String(requestedJobId);
376
+ }
367
377
  throw ErrorFactory.createTryCatchError('Failed to enqueue job via BullMQ', error);
368
378
  }
369
379
  },
@@ -153,11 +153,58 @@ const callGateway = async (action, payload) => {
153
153
  throw error;
154
154
  }
155
155
  };
156
+ const resolveFallbackJobId = (payload) => {
157
+ if (typeof payload.uniqueId === 'string' && payload.uniqueId.trim().length > 0) {
158
+ return payload.uniqueId.trim();
159
+ }
160
+ return generateUuid();
161
+ };
162
+ const resolveCurrentAttempts = (payload) => {
163
+ const raw = payload['_currentAttempts'];
164
+ if (typeof raw !== 'number' || Number.isFinite(raw) === false)
165
+ return 0;
166
+ return Math.max(0, Math.floor(raw));
167
+ };
168
+ const resolveMaxAttempts = (payload) => {
169
+ if (typeof payload.attempts === 'number' && Number.isFinite(payload.attempts)) {
170
+ return Math.max(1, Math.floor(payload.attempts));
171
+ }
172
+ return undefined;
173
+ };
174
+ const resolveIdempotencyKey = (payload) => {
175
+ if (typeof payload.uniqueId !== 'string')
176
+ return undefined;
177
+ const trimmed = payload.uniqueId.trim();
178
+ return trimmed.length > 0 ? trimmed : undefined;
179
+ };
180
+ const markPendingRecoveryFallback = async (input) => {
181
+ const currentAttempts = resolveCurrentAttempts(input.payload);
182
+ const maxAttempts = resolveMaxAttempts(input.payload);
183
+ const idempotencyKey = resolveIdempotencyKey(input.payload);
184
+ // Compatibility shim: consumers of `@zintrust/core` may have a narrower
185
+ // `JobStateTracker.enqueued` type than the runtime implementation.
186
+ const enqueuedApi = JobStateTracker;
187
+ await enqueuedApi.enqueued({
188
+ queueName: input.queue,
189
+ jobId: input.fallbackJobId,
190
+ payload: input.payload,
191
+ attempts: currentAttempts,
192
+ maxAttempts,
193
+ idempotencyKey,
194
+ });
195
+ const pendingRecoveryApi = JobStateTracker;
196
+ if (typeof pendingRecoveryApi.pendingRecovery === 'function') {
197
+ await pendingRecoveryApi.pendingRecovery({
198
+ queueName: input.queue,
199
+ jobId: input.fallbackJobId,
200
+ reason: 'HTTP queue proxy enqueue failed; marked pending recovery',
201
+ error: input.error,
202
+ });
203
+ }
204
+ };
156
205
  export const HttpQueueDriver = Object.freeze({
157
206
  async enqueue(queue, payload) {
158
- const fallbackJobId = typeof payload.uniqueId === 'string' && payload.uniqueId.trim().length > 0
159
- ? payload.uniqueId.trim()
160
- : generateUuid();
207
+ const fallbackJobId = resolveFallbackJobId(payload);
161
208
  const timeoutMs = Env.getInt('QUEUE_HTTP_PROXY_TIMEOUT_MS', 10000);
162
209
  try {
163
210
  return await TimeoutManager.withTimeoutRetry(async () => callGateway('enqueue', { queue, payload }), {
@@ -173,26 +220,12 @@ export const HttpQueueDriver = Object.freeze({
173
220
  fallbackJobId,
174
221
  error: error instanceof Error ? error.message : String(error),
175
222
  });
176
- await JobStateTracker.enqueued({
177
- queueName: queue,
178
- jobId: fallbackJobId,
223
+ await markPendingRecoveryFallback({
224
+ queue,
225
+ fallbackJobId,
179
226
  payload,
180
- maxAttempts: typeof payload.attempts === 'number' && Number.isFinite(payload.attempts)
181
- ? Math.max(1, Math.floor(payload.attempts))
182
- : undefined,
183
- idempotencyKey: typeof payload.uniqueId === 'string' && payload.uniqueId.trim().length > 0
184
- ? payload.uniqueId.trim()
185
- : undefined,
227
+ error,
186
228
  });
187
- const pendingRecoveryApi = JobStateTracker;
188
- if (typeof pendingRecoveryApi.pendingRecovery === 'function') {
189
- await pendingRecoveryApi.pendingRecovery({
190
- queueName: queue,
191
- jobId: fallbackJobId,
192
- reason: 'HTTP queue proxy enqueue failed; marked pending recovery',
193
- error,
194
- });
195
- }
196
229
  Logger.warn('Job marked pending recovery in tracker', {
197
230
  queue,
198
231
  jobId: fallbackJobId,
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@zintrust/queue-redis",
3
3
  "version": "0.1.27",
4
- "buildDate": "2026-02-15T07:17:27.370Z",
4
+ "buildDate": "2026-02-19T05:36:54.195Z",
5
5
  "buildEnvironment": {
6
6
  "node": "v20.20.0",
7
7
  "platform": "linux",
8
8
  "arch": "x64"
9
9
  },
10
10
  "git": {
11
- "commit": "33b681d",
11
+ "commit": "4e0a37b",
12
12
  "branch": "master"
13
13
  },
14
14
  "package": {
@@ -29,16 +29,16 @@
29
29
  "sha256": "52fb0f688cd17cc7d8e8128e60df6f5eea4c803282382ac75550e6aacee7cbb0"
30
30
  },
31
31
  "BullMQRedisQueue.js": {
32
- "size": 19557,
33
- "sha256": "28719e3ec86045a4c837a2d0f698b5b7825e74344e8b65caa4b4d9f4359214ff"
32
+ "size": 20130,
33
+ "sha256": "25e6fb6928236fe10959d2d6a3849ee7845d89e7469b12e57d4f945d32f7304f"
34
34
  },
35
35
  "HttpQueueDriver.d.ts": {
36
36
  "size": 835,
37
37
  "sha256": "31735e10a83cf905ca48f3bf1c79f40029b9ac7c0ce6c26751ad646fa77bc764"
38
38
  },
39
39
  "HttpQueueDriver.js": {
40
- "size": 7984,
41
- "sha256": "daec8d2ba999d1f189e446432122a5bcc347bc65c6de9cf5408f35de233c3933"
40
+ "size": 8967,
41
+ "sha256": "1ed2cbcee0df24c42760222eb2cab2fac21d4547c153453ce4a8623e5b83b5c3"
42
42
  },
43
43
  "QueueHttpGateway.d.ts": {
44
44
  "size": 432,
@@ -62,7 +62,7 @@
62
62
  },
63
63
  "index.js": {
64
64
  "size": 671,
65
- "sha256": "43528a869c085982e10a862c71af41a1bbaa22081d2cd88c5781c0306f1b054c"
65
+ "sha256": "64c9722bed8ffd25b1a4717f206b12b58b997e374d8c09ee1bf373658a092360"
66
66
  },
67
67
  "register.d.ts": {
68
68
  "size": 169,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zintrust/queue-redis",
3
- "version": "0.1.41",
3
+ "version": "0.1.43",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "node": ">=20.0.0"
23
23
  },
24
24
  "peerDependencies": {
25
- "@zintrust/core": "^0.1.41"
25
+ "@zintrust/core": "^0.1.43"
26
26
  },
27
27
  "publishConfig": {
28
28
  "access": "public"