bunqueue 2.0.2 → 2.0.3

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 (90) hide show
  1. package/dist/application/backgroundTasks.d.ts.map +1 -1
  2. package/dist/application/backgroundTasks.js +105 -29
  3. package/dist/application/backgroundTasks.js.map +1 -1
  4. package/dist/application/operations/jobManagement.d.ts.map +1 -1
  5. package/dist/application/operations/jobManagement.js +1 -0
  6. package/dist/application/operations/jobManagement.js.map +1 -1
  7. package/dist/application/queueManager.d.ts +8 -0
  8. package/dist/application/queueManager.d.ts.map +1 -1
  9. package/dist/application/queueManager.js +40 -0
  10. package/dist/application/queueManager.js.map +1 -1
  11. package/dist/client/queue/bullmqCompat.d.ts +46 -0
  12. package/dist/client/queue/bullmqCompat.d.ts.map +1 -0
  13. package/dist/client/queue/bullmqCompat.js +97 -0
  14. package/dist/client/queue/bullmqCompat.js.map +1 -0
  15. package/dist/client/queue/deduplication.d.ts +13 -0
  16. package/dist/client/queue/deduplication.d.ts.map +1 -0
  17. package/dist/client/queue/deduplication.js +24 -0
  18. package/dist/client/queue/deduplication.js.map +1 -0
  19. package/dist/client/queue/dlq.d.ts +31 -0
  20. package/dist/client/queue/dlq.d.ts.map +1 -0
  21. package/dist/client/queue/dlq.js +85 -0
  22. package/dist/client/queue/dlq.js.map +1 -0
  23. package/dist/client/queue/jobMove.d.ts +33 -0
  24. package/dist/client/queue/jobMove.d.ts.map +1 -0
  25. package/dist/client/queue/jobMove.js +113 -0
  26. package/dist/client/queue/jobMove.js.map +1 -0
  27. package/dist/client/queue/jobProxy.d.ts +28 -0
  28. package/dist/client/queue/jobProxy.d.ts.map +1 -0
  29. package/dist/client/queue/jobProxy.js +209 -0
  30. package/dist/client/queue/jobProxy.js.map +1 -0
  31. package/dist/client/queue/operations/add.d.ts +47 -0
  32. package/dist/client/queue/operations/add.d.ts.map +1 -0
  33. package/dist/client/queue/operations/add.js +226 -0
  34. package/dist/client/queue/operations/add.js.map +1 -0
  35. package/dist/client/queue/operations/control.d.ts +26 -0
  36. package/dist/client/queue/operations/control.d.ts.map +1 -0
  37. package/dist/client/queue/operations/control.js +56 -0
  38. package/dist/client/queue/operations/control.js.map +1 -0
  39. package/dist/client/queue/operations/counts.d.ts +40 -0
  40. package/dist/client/queue/operations/counts.d.ts.map +1 -0
  41. package/dist/client/queue/operations/counts.js +99 -0
  42. package/dist/client/queue/operations/counts.js.map +1 -0
  43. package/dist/client/queue/operations/index.d.ts +10 -0
  44. package/dist/client/queue/operations/index.d.ts.map +1 -0
  45. package/dist/client/queue/operations/index.js +10 -0
  46. package/dist/client/queue/operations/index.js.map +1 -0
  47. package/dist/client/queue/operations/management.d.ts +56 -0
  48. package/dist/client/queue/operations/management.d.ts.map +1 -0
  49. package/dist/client/queue/operations/management.js +181 -0
  50. package/dist/client/queue/operations/management.js.map +1 -0
  51. package/dist/client/queue/operations/query.d.ts +58 -0
  52. package/dist/client/queue/operations/query.d.ts.map +1 -0
  53. package/dist/client/queue/operations/query.js +191 -0
  54. package/dist/client/queue/operations/query.js.map +1 -0
  55. package/dist/client/queue/queue.d.ts +93 -272
  56. package/dist/client/queue/queue.d.ts.map +1 -1
  57. package/dist/client/queue/queue.js +297 -1599
  58. package/dist/client/queue/queue.js.map +1 -1
  59. package/dist/client/queue/queueTypes.d.ts +34 -0
  60. package/dist/client/queue/queueTypes.d.ts.map +1 -0
  61. package/dist/client/queue/queueTypes.js +6 -0
  62. package/dist/client/queue/queueTypes.js.map +1 -0
  63. package/dist/client/queue/rateLimit.d.ts +32 -0
  64. package/dist/client/queue/rateLimit.d.ts.map +1 -0
  65. package/dist/client/queue/rateLimit.js +69 -0
  66. package/dist/client/queue/rateLimit.js.map +1 -0
  67. package/dist/client/queue/scheduler.d.ts +44 -0
  68. package/dist/client/queue/scheduler.d.ts.map +1 -0
  69. package/dist/client/queue/scheduler.js +114 -0
  70. package/dist/client/queue/scheduler.js.map +1 -0
  71. package/dist/client/queue/stall.d.ts +15 -0
  72. package/dist/client/queue/stall.d.ts.map +1 -0
  73. package/dist/client/queue/stall.js +21 -0
  74. package/dist/client/queue/stall.js.map +1 -0
  75. package/dist/client/queue/workers.d.ts +29 -0
  76. package/dist/client/queue/workers.d.ts.map +1 -0
  77. package/dist/client/queue/workers.js +39 -0
  78. package/dist/client/queue/workers.js.map +1 -0
  79. package/dist/client/sandboxed/worker.d.ts.map +1 -1
  80. package/dist/client/sandboxed/worker.js +12 -1
  81. package/dist/client/sandboxed/worker.js.map +1 -1
  82. package/dist/infrastructure/persistence/sqlite.d.ts +21 -2
  83. package/dist/infrastructure/persistence/sqlite.d.ts.map +1 -1
  84. package/dist/infrastructure/persistence/sqlite.js +35 -6
  85. package/dist/infrastructure/persistence/sqlite.js.map +1 -1
  86. package/dist/infrastructure/server/handlers/query.d.ts +1 -1
  87. package/dist/infrastructure/server/handlers/query.d.ts.map +1 -1
  88. package/dist/infrastructure/server/handlers/query.js +4 -11
  89. package/dist/infrastructure/server/handlers/query.js.map +1 -1
  90. package/package.json +1 -1
@@ -2,12 +2,22 @@
2
2
  * Queue
3
3
  * BullMQ-style queue for job management
4
4
  */
5
- import { getSharedManager } from '../manager';
6
5
  import { TcpConnectionPool, getSharedPool, releaseSharedPool } from '../tcpPool';
7
- import { toPublicJob } from '../types';
8
- import { jobId } from '../../domain/types/job';
9
6
  import { FORCE_EMBEDDED } from './helpers';
10
- import * as dlqOps from './dlqOps';
7
+ // Import operation modules
8
+ import * as addOps from './operations/add';
9
+ import * as queryOps from './operations/query';
10
+ import * as countsOps from './operations/counts';
11
+ import * as controlOps from './operations/control';
12
+ import * as managementOps from './operations/management';
13
+ import * as stallOps from './stall';
14
+ import * as dlqOps from './dlq';
15
+ import * as rateLimitOps from './rateLimit';
16
+ import * as schedulerOps from './scheduler';
17
+ import * as deduplicationOps from './deduplication';
18
+ import * as jobMoveOps from './jobMove';
19
+ import * as workersOps from './workers';
20
+ import * as bullmqCompatOps from './bullmqCompat';
11
21
  /**
12
22
  * Queue class for adding and managing jobs
13
23
  */
@@ -43,1477 +53,368 @@ export class Queue {
43
53
  }
44
54
  }
45
55
  }
46
- get tcp() {
47
- if (!this.tcpPool)
48
- throw new Error('No TCP connection available');
49
- return this.tcpPool;
50
- }
51
- /** Add a job to the queue */
52
- async add(name, data, opts = {}) {
53
- const merged = { ...this.opts.defaultJobOptions, ...opts };
54
- // Add parent info to data if specified (BullMQ v5 flow support)
55
- const jobData = { name, ...data };
56
- if (merged.parent) {
57
- jobData.__parentId = merged.parent.id;
58
- jobData.__parentQueue = merged.parent.queue;
59
- }
60
- if (this.embedded) {
61
- const manager = getSharedManager();
62
- // Parse removeOnComplete/removeOnFail (can be boolean, number, or KeepJobs)
63
- const removeOnComplete = typeof merged.removeOnComplete === 'boolean' ? merged.removeOnComplete : false;
64
- const removeOnFail = typeof merged.removeOnFail === 'boolean' ? merged.removeOnFail : false;
65
- // Parse repeat options with extended BullMQ v5 fields
66
- const repeat = merged.repeat
67
- ? {
68
- every: merged.repeat.every,
69
- limit: merged.repeat.limit,
70
- pattern: merged.repeat.pattern,
71
- count: merged.repeat.count,
72
- startDate: merged.repeat.startDate instanceof Date
73
- ? merged.repeat.startDate.getTime()
74
- : typeof merged.repeat.startDate === 'string'
75
- ? new Date(merged.repeat.startDate).getTime()
76
- : merged.repeat.startDate,
77
- endDate: merged.repeat.endDate instanceof Date
78
- ? merged.repeat.endDate.getTime()
79
- : typeof merged.repeat.endDate === 'string'
80
- ? new Date(merged.repeat.endDate).getTime()
81
- : merged.repeat.endDate,
82
- tz: merged.repeat.tz,
83
- immediately: merged.repeat.immediately,
84
- prevMillis: merged.repeat.prevMillis,
85
- offset: merged.repeat.offset,
86
- jobId: merged.repeat.jobId,
87
- }
88
- : undefined;
89
- const job = await manager.push(this.name, {
90
- data: jobData,
91
- priority: merged.priority,
92
- delay: merged.delay,
93
- maxAttempts: merged.attempts,
94
- backoff: merged.backoff,
95
- timeout: merged.timeout,
96
- customId: merged.jobId ?? merged.deduplication?.id,
97
- removeOnComplete,
98
- removeOnFail,
99
- repeat,
100
- stallTimeout: merged.stallTimeout,
101
- durable: merged.durable,
102
- parentId: merged.parent ? jobId(merged.parent.id) : undefined,
103
- // BullMQ v5 options
104
- lifo: merged.lifo,
105
- stackTraceLimit: merged.stackTraceLimit,
106
- keepLogs: merged.keepLogs,
107
- sizeLimit: merged.sizeLimit,
108
- failParentOnFailure: merged.failParentOnFailure,
109
- removeDependencyOnFailure: merged.removeDependencyOnFailure,
110
- dedup: merged.deduplication ? { ttl: merged.deduplication.ttl } : undefined,
111
- debounceId: merged.debounce?.id,
112
- debounceTtl: merged.debounce?.ttl,
113
- });
114
- return toPublicJob({
115
- job,
116
- name,
117
- getState: (jid) => this.getJobState(jid),
118
- remove: (jid) => this.removeAsync(jid),
119
- retry: (jid) => this.retryJob(jid),
120
- getChildrenValues: (jid) => this.getChildrenValues(jid),
121
- updateData: (jid, data) => this.updateJobData(jid, data),
122
- promote: (jid) => this.promoteJob(jid),
123
- changeDelay: (jid, delay) => this.changeJobDelay(jid, delay),
124
- changePriority: (jid, opts) => this.changeJobPriority(jid, opts),
125
- extendLock: (jid, token, duration) => this.extendJobLock(jid, token, duration),
126
- clearLogs: (jid, keepLogs) => this.clearJobLogs(jid, keepLogs),
127
- getDependencies: (jid, opts) => this.getJobDependencies(jid, opts),
128
- getDependenciesCount: (jid, opts) => this.getJobDependenciesCount(jid, opts),
129
- moveToCompleted: (jid, result, token) => this.moveJobToCompleted(jid, result, token),
130
- moveToFailed: (jid, error, token) => this.moveJobToFailed(jid, error, token),
131
- moveToWait: (jid, token) => this.moveJobToWait(jid, token),
132
- moveToDelayed: (jid, timestamp, token) => this.moveJobToDelayed(jid, timestamp, token),
133
- moveToWaitingChildren: (jid, token, opts) => this.moveJobToWaitingChildren(jid, token, opts),
134
- waitUntilFinished: (jid, queueEvents, ttl) => this.waitJobUntilFinished(jid, queueEvents, ttl),
135
- });
136
- }
137
- const response = await this.tcp.send({
138
- cmd: 'PUSH',
139
- queue: this.name,
140
- data: jobData,
141
- priority: merged.priority,
142
- delay: merged.delay,
143
- maxAttempts: merged.attempts,
144
- backoff: merged.backoff,
145
- timeout: merged.timeout,
146
- jobId: merged.jobId,
147
- removeOnComplete: merged.removeOnComplete,
148
- removeOnFail: merged.removeOnFail,
149
- stallTimeout: merged.stallTimeout,
150
- durable: merged.durable,
151
- repeat: merged.repeat,
152
- parentId: merged.parent?.id,
153
- });
154
- if (!response.ok) {
155
- throw new Error(response.error ?? 'Failed to add job');
156
- }
157
- const jobIdStr = response.id;
158
- return this.createJobProxy(jobIdStr, name, data);
159
- }
160
- /** Add multiple jobs (batch optimized) */
161
- async addBulk(jobs) {
162
- if (jobs.length === 0)
163
- return [];
164
- const now = Date.now();
165
- if (this.embedded) {
166
- const manager = getSharedManager();
167
- const inputs = jobs.map(({ name, data, opts }) => {
168
- const m = { ...this.opts.defaultJobOptions, ...opts };
169
- // Parse removeOnComplete/removeOnFail (can be boolean, number, or KeepJobs)
170
- const removeOnComplete = typeof m.removeOnComplete === 'boolean' ? m.removeOnComplete : false;
171
- const removeOnFail = typeof m.removeOnFail === 'boolean' ? m.removeOnFail : false;
172
- return {
173
- data: { name, ...data },
174
- priority: m.priority,
175
- delay: m.delay,
176
- maxAttempts: m.attempts,
177
- backoff: m.backoff,
178
- timeout: m.timeout,
179
- customId: m.jobId,
180
- removeOnComplete,
181
- removeOnFail,
182
- repeat: m.repeat
183
- ? {
184
- every: m.repeat.every,
185
- limit: m.repeat.limit,
186
- pattern: m.repeat.pattern,
187
- count: m.repeat.count,
188
- startDate: m.repeat.startDate instanceof Date
189
- ? m.repeat.startDate.getTime()
190
- : typeof m.repeat.startDate === 'string'
191
- ? new Date(m.repeat.startDate).getTime()
192
- : m.repeat.startDate,
193
- endDate: m.repeat.endDate instanceof Date
194
- ? m.repeat.endDate.getTime()
195
- : typeof m.repeat.endDate === 'string'
196
- ? new Date(m.repeat.endDate).getTime()
197
- : m.repeat.endDate,
198
- tz: m.repeat.tz,
199
- immediately: m.repeat.immediately,
200
- prevMillis: m.repeat.prevMillis,
201
- offset: m.repeat.offset,
202
- jobId: m.repeat.jobId,
203
- }
204
- : undefined,
205
- stallTimeout: m.stallTimeout,
206
- durable: m.durable,
207
- // BullMQ v5 options
208
- lifo: m.lifo,
209
- stackTraceLimit: m.stackTraceLimit,
210
- keepLogs: m.keepLogs,
211
- sizeLimit: m.sizeLimit,
212
- failParentOnFailure: m.failParentOnFailure,
213
- removeDependencyOnFailure: m.removeDependencyOnFailure,
214
- dedup: m.deduplication ? { ttl: m.deduplication.ttl } : undefined,
215
- debounceId: m.debounce?.id,
216
- debounceTtl: m.debounce?.ttl,
217
- };
218
- });
219
- const ids = await manager.pushBatch(this.name, inputs);
220
- return ids.map((id, i) => this.createSimpleJob(String(id), jobs[i].name, jobs[i].data, now));
221
- }
222
- const jobInputs = jobs.map(({ name, data, opts }) => {
223
- const m = { ...this.opts.defaultJobOptions, ...opts };
224
- return {
225
- data: { name, ...data },
226
- priority: m.priority,
227
- delay: m.delay,
228
- maxAttempts: m.attempts,
229
- backoff: m.backoff,
230
- timeout: m.timeout,
231
- customId: m.jobId,
232
- removeOnComplete: m.removeOnComplete,
233
- removeOnFail: m.removeOnFail,
234
- stallTimeout: m.stallTimeout,
235
- repeat: m.repeat,
236
- durable: m.durable,
237
- };
238
- });
239
- const response = await this.tcp.send({ cmd: 'PUSHB', queue: this.name, jobs: jobInputs });
240
- if (!response.ok) {
241
- throw new Error(response.error ?? 'Failed to add jobs');
242
- }
243
- const ids = response.ids;
244
- return ids.map((id, i) => this.createSimpleJob(id, jobs[i].name, jobs[i].data, now));
56
+ // Context builders for modules
57
+ get ctx() {
58
+ return { name: this.name, embedded: this.embedded, tcp: this.tcpPool };
245
59
  }
246
- /** Get a job by ID */
247
- async getJob(id) {
248
- if (this.embedded) {
249
- const manager = getSharedManager();
250
- const job = await manager.getJob(jobId(id));
251
- if (!job)
252
- return null;
253
- const jobData = job.data;
254
- return toPublicJob({
255
- job,
256
- name: jobData?.name ?? 'default',
257
- getState: (jid) => this.getJobState(jid),
258
- remove: (jid) => this.removeAsync(jid),
259
- retry: (jid) => this.retryJob(jid),
260
- getChildrenValues: (jid) => this.getChildrenValues(jid),
261
- updateData: (jid, data) => this.updateJobData(jid, data),
262
- promote: (jid) => this.promoteJob(jid),
263
- changeDelay: (jid, delay) => this.changeJobDelay(jid, delay),
264
- changePriority: (jid, opts) => this.changeJobPriority(jid, opts),
265
- extendLock: (jid, token, duration) => this.extendJobLock(jid, token, duration),
266
- clearLogs: (jid, keepLogs) => this.clearJobLogs(jid, keepLogs),
267
- getDependencies: (jid, opts) => this.getJobDependencies(jid, opts),
268
- getDependenciesCount: (jid, opts) => this.getJobDependenciesCount(jid, opts),
269
- moveToCompleted: (jid, result, token) => this.moveJobToCompleted(jid, result, token),
270
- moveToFailed: (jid, error, token) => this.moveJobToFailed(jid, error, token),
271
- moveToWait: (jid, token) => this.moveJobToWait(jid, token),
272
- moveToDelayed: (jid, timestamp, token) => this.moveJobToDelayed(jid, timestamp, token),
273
- moveToWaitingChildren: (jid, token, opts) => this.moveJobToWaitingChildren(jid, token, opts),
274
- waitUntilFinished: (jid, queueEvents, ttl) => this.waitJobUntilFinished(jid, queueEvents, ttl),
275
- });
276
- }
277
- const response = await this.tcp.send({ cmd: 'GetJob', id });
278
- if (!response.ok || !response.job)
279
- return null;
280
- const jobData = response.job;
281
- const data = jobData.data;
282
- const jobIdStr = String(jobData.id);
283
- const ts = jobData.createdAt ?? Date.now();
284
- const runAt = jobData.runAt ?? ts;
60
+ get addCtx() {
285
61
  return {
286
- id: jobIdStr,
287
- name: data?.name ?? 'default',
288
- data: jobData.data,
289
- queueName: this.name,
290
- attemptsMade: jobData.attempts ?? 0,
291
- timestamp: ts,
292
- progress: jobData.progress ?? 0,
293
- // BullMQ v5 properties
294
- delay: runAt > ts ? runAt - ts : 0,
295
- processedOn: jobData.startedAt ?? undefined,
296
- finishedOn: jobData.completedAt ?? undefined,
297
- stacktrace: null,
298
- stalledCounter: jobData.stallCount ?? 0,
299
- priority: jobData.priority ?? 0,
300
- parentKey: undefined,
301
- opts: {},
302
- token: undefined,
303
- processedBy: undefined,
304
- deduplicationId: jobData.customId ?? undefined,
305
- repeatJobKey: undefined,
306
- attemptsStarted: jobData.attempts ?? 0,
307
- // Methods
308
- updateProgress: async () => { },
309
- log: async () => { },
310
- getState: () => this.getJobState(jobIdStr),
311
- remove: () => this.removeAsync(jobIdStr),
312
- retry: () => this.retryJob(jobIdStr),
313
- getChildrenValues: () => this.getChildrenValues(jobIdStr),
314
- // BullMQ v5 state check methods
315
- isWaiting: async () => (await this.getJobState(jobIdStr)) === 'waiting',
316
- isActive: async () => (await this.getJobState(jobIdStr)) === 'active',
317
- isDelayed: async () => (await this.getJobState(jobIdStr)) === 'delayed',
318
- isCompleted: async () => (await this.getJobState(jobIdStr)) === 'completed',
319
- isFailed: async () => (await this.getJobState(jobIdStr)) === 'failed',
320
- isWaitingChildren: () => Promise.resolve(false),
321
- // BullMQ v5 mutation methods
322
- updateData: async () => { },
323
- promote: async () => { },
324
- changeDelay: async () => { },
325
- changePriority: async () => { },
326
- extendLock: () => Promise.resolve(0),
327
- clearLogs: async () => { },
328
- // BullMQ v5 dependency methods
329
- getDependencies: () => Promise.resolve({ processed: {}, unprocessed: [] }),
330
- getDependenciesCount: () => Promise.resolve({ processed: 0, unprocessed: 0 }),
331
- // BullMQ v5 serialization methods
332
- toJSON: () => ({
333
- id: jobIdStr,
334
- name: data?.name ?? 'default',
335
- data: jobData.data,
336
- opts: {},
337
- progress: jobData.progress ?? 0,
338
- delay: runAt > ts ? runAt - ts : 0,
339
- timestamp: ts,
340
- attemptsMade: jobData.attempts ?? 0,
341
- stacktrace: null,
342
- queueQualifiedName: `bull:${this.name}`,
343
- }),
344
- asJSON: () => ({
345
- id: jobIdStr,
346
- name: data?.name ?? 'default',
347
- data: JSON.stringify(jobData.data),
348
- opts: '{}',
349
- progress: String(jobData.progress ?? 0),
350
- delay: String(runAt > ts ? runAt - ts : 0),
351
- timestamp: String(ts),
352
- attemptsMade: String(jobData.attempts ?? 0),
353
- stacktrace: null,
354
- }),
355
- // BullMQ v5 move methods
356
- moveToCompleted: () => Promise.resolve(null),
357
- moveToFailed: () => Promise.resolve(),
358
- moveToWait: () => Promise.resolve(false),
359
- moveToDelayed: () => Promise.resolve(),
360
- moveToWaitingChildren: () => Promise.resolve(false),
361
- waitUntilFinished: () => Promise.resolve(undefined),
362
- // BullMQ v5 additional methods
363
- discard: () => { },
364
- getFailedChildrenValues: () => Promise.resolve({}),
365
- getIgnoredChildrenFailures: () => Promise.resolve({}),
366
- removeChildDependency: () => Promise.resolve(false),
367
- removeDeduplicationKey: () => Promise.resolve(false),
368
- removeUnprocessedChildren: () => Promise.resolve(),
62
+ ...this.ctx,
63
+ opts: this.opts,
64
+ getJobState: (id) => this.getJobState(id),
65
+ removeAsync: (id) => this.removeAsync(id),
66
+ retryJob: (id) => this.retryJob(id),
67
+ getChildrenValues: (id) => this.getChildrenValues(id),
68
+ updateJobData: (id, data) => this.updateJobData(id, data),
69
+ promoteJob: (id) => this.promoteJob(id),
70
+ changeJobDelay: (id, delay) => this.changeJobDelay(id, delay),
71
+ changeJobPriority: (id, opts) => this.changeJobPriority(id, opts),
72
+ extendJobLock: (id, token, dur) => this.extendJobLock(id, token, dur),
73
+ clearJobLogs: (id, keep) => this.clearJobLogs(id, keep),
74
+ getJobDependencies: (id, o) => this.getJobDependencies(id, o),
75
+ getJobDependenciesCount: (id, o) => this.getJobDependenciesCount(id, o),
76
+ moveJobToCompleted: (id, r, t) => this.moveJobToCompleted(id, r, t),
77
+ moveJobToFailed: (id, e, t) => this.moveJobToFailed(id, e, t),
78
+ moveJobToWait: (id, t) => this.moveJobToWait(id, t),
79
+ moveJobToDelayed: (id, ts, t) => this.moveJobToDelayed(id, ts, t),
80
+ moveJobToWaitingChildren: (id, t, o) => this.moveJobToWaitingChildren(id, t, o),
81
+ waitJobUntilFinished: (id, qe, ttl) => this.waitJobUntilFinished(id, qe, ttl),
369
82
  };
370
83
  }
371
- /** Remove a job by ID */
372
- remove(id) {
373
- if (this.embedded)
374
- void getSharedManager().cancel(jobId(id));
375
- else
376
- void this.tcp.send({ cmd: 'Cancel', id });
84
+ get queryCtx() {
85
+ return {
86
+ ...this.ctx,
87
+ getJobState: (id) => this.getJobState(id),
88
+ removeAsync: (id) => this.removeAsync(id),
89
+ retryJob: (id) => this.retryJob(id),
90
+ getChildrenValues: (id) => this.getChildrenValues(id),
91
+ // Extended context for toPublicJob (full opts support)
92
+ updateJobData: (id, data) => this.updateJobData(id, data),
93
+ promoteJob: (id) => this.promoteJob(id),
94
+ changeJobDelay: (id, delay) => this.changeJobDelay(id, delay),
95
+ changeJobPriority: (id, opts) => this.changeJobPriority(id, opts),
96
+ extendJobLock: (id, token, dur) => this.extendJobLock(id, token, dur),
97
+ clearJobLogs: (id, keep) => this.clearJobLogs(id, keep),
98
+ getJobDependencies: (id, o) => this.getJobDependencies(id, o),
99
+ getJobDependenciesCount: (id, o) => this.getJobDependenciesCount(id, o),
100
+ };
377
101
  }
378
- /** Remove a job by ID (async) */
379
- async removeAsync(id) {
380
- if (this.embedded) {
381
- await getSharedManager().cancel(jobId(id));
382
- }
383
- else {
384
- await this.tcp.send({ cmd: 'Cancel', id });
385
- }
102
+ get moveCtx() {
103
+ return {
104
+ ...this.ctx,
105
+ getJobState: (id) => this.getJobState(id),
106
+ getJobDependencies: (id) => this.getJobDependencies(id),
107
+ };
386
108
  }
387
- /** Retry a job by ID */
388
- async retryJob(id) {
389
- if (this.embedded) {
390
- // For embedded mode, we need to implement retry in QueueManager
391
- // For now, just get the job and re-add it
392
- const manager = getSharedManager();
393
- const job = await manager.getJob(jobId(id));
394
- if (job) {
395
- await manager.push(job.queue, { data: job.data, priority: job.priority });
396
- }
397
- }
398
- else {
399
- await this.tcp.send({ cmd: 'RetryJob', id });
400
- }
109
+ // ============ Add Operations ============
110
+ add(name, data, opts) {
111
+ return addOps.add(this.addCtx, name, data, opts);
112
+ }
113
+ addBulk(jobs) {
114
+ return addOps.addBulk(this.addCtx, jobs);
115
+ }
116
+ // ============ Query Operations ============
117
+ getJob(id) {
118
+ return queryOps.getJob(this.queryCtx, id);
119
+ }
120
+ getJobState(id) {
121
+ return queryOps.getJobState(this.queryCtx, id);
401
122
  }
402
- /**
403
- * Get the return values of all children jobs (BullMQ v5 compatible).
404
- * Returns a Record where keys are job keys (queueName:jobId) and values are return values.
405
- */
406
123
  getChildrenValues(id) {
407
- if (this.embedded) {
408
- const manager = getSharedManager();
409
- return manager.getChildrenValues(jobId(id));
410
- }
411
- // TCP mode - would need server-side support
412
- // For now, return empty object
413
- return Promise.resolve({});
124
+ return queryOps.getChildrenValues(this.queryCtx, id);
414
125
  }
415
- /** Get job state by ID (async, works with both embedded and TCP) */
416
- async getJobState(id) {
417
- if (this.embedded) {
418
- const manager = getSharedManager();
419
- const state = await manager.getJobState(jobId(id));
420
- return state;
421
- }
422
- const response = await this.tcp.send({ cmd: 'GetState', id });
423
- if (!response.ok)
424
- return 'unknown';
425
- return response.state;
126
+ getJobs(opts) {
127
+ return queryOps.getJobs(this.queryCtx, opts);
128
+ }
129
+ getJobsAsync(opts) {
130
+ return queryOps.getJobsAsync(this.queryCtx, opts);
131
+ }
132
+ getWaiting(start, end) {
133
+ return queryOps.getWaiting(this.queryCtx, start, end);
134
+ }
135
+ getWaitingAsync(start, end) {
136
+ return queryOps.getWaitingAsync(this.queryCtx, start, end);
137
+ }
138
+ getDelayed(start, end) {
139
+ return queryOps.getDelayed(this.queryCtx, start, end);
140
+ }
141
+ getDelayedAsync(start, end) {
142
+ return queryOps.getDelayedAsync(this.queryCtx, start, end);
143
+ }
144
+ getActive(start, end) {
145
+ return queryOps.getActive(this.queryCtx, start, end);
146
+ }
147
+ getActiveAsync(start, end) {
148
+ return queryOps.getActiveAsync(this.queryCtx, start, end);
426
149
  }
427
- /** Get job counts by state */
150
+ getCompleted(start, end) {
151
+ return queryOps.getCompleted(this.queryCtx, start, end);
152
+ }
153
+ getCompletedAsync(start, end) {
154
+ return queryOps.getCompletedAsync(this.queryCtx, start, end);
155
+ }
156
+ getFailed(start, end) {
157
+ return queryOps.getFailed(this.queryCtx, start, end);
158
+ }
159
+ getFailedAsync(start, end) {
160
+ return queryOps.getFailedAsync(this.queryCtx, start, end);
161
+ }
162
+ // ============ Count Operations ============
428
163
  getJobCounts() {
429
- if (this.embedded) {
430
- const s = getSharedManager().getStats();
431
- return { waiting: s.waiting, active: s.active, completed: s.completed, failed: s.dlq };
432
- }
433
- return { waiting: 0, active: 0, completed: 0, failed: 0 };
434
- }
435
- /** Get job counts (async, works with TCP) */
436
- async getJobCountsAsync() {
437
- if (this.embedded)
438
- return this.getJobCounts();
439
- const response = await this.tcp.send({ cmd: 'Stats' });
440
- if (!response.ok)
441
- return { waiting: 0, active: 0, completed: 0, failed: 0 };
442
- const s = response.stats;
443
- return {
444
- waiting: s?.queued ?? 0,
445
- active: s?.processing ?? 0,
446
- completed: s?.completed ?? 0,
447
- failed: s?.dlq ?? 0,
448
- };
164
+ return countsOps.getJobCounts(this.ctx);
165
+ }
166
+ getJobCountsAsync() {
167
+ return countsOps.getJobCountsAsync(this.ctx);
168
+ }
169
+ getWaitingCount() {
170
+ return countsOps.getWaitingCount(this.ctx);
171
+ }
172
+ getActiveCount() {
173
+ return countsOps.getActiveCount(this.ctx);
174
+ }
175
+ getCompletedCount() {
176
+ return countsOps.getCompletedCount(this.ctx);
177
+ }
178
+ getFailedCount() {
179
+ return countsOps.getFailedCount(this.ctx);
180
+ }
181
+ getDelayedCount() {
182
+ return countsOps.getDelayedCount(this.ctx);
183
+ }
184
+ count() {
185
+ return countsOps.count(this.ctx);
186
+ }
187
+ countAsync() {
188
+ return countsOps.countAsync(this.ctx);
449
189
  }
450
- /** Get job counts grouped by priority */
451
190
  getCountsPerPriority() {
452
- if (this.embedded) {
453
- return getSharedManager().getCountsPerPriority(this.name);
454
- }
455
- // TCP mode returns empty for sync - use getCountsPerPriorityAsync
456
- return {};
457
- }
458
- /** Get job counts grouped by priority (async, works with TCP) */
459
- async getCountsPerPriorityAsync() {
460
- if (this.embedded)
461
- return this.getCountsPerPriority();
462
- const response = await this.tcp.send({ cmd: 'GetCountsPerPriority', queue: this.name });
463
- if (!response.ok)
464
- return {};
465
- return response.counts ?? {};
191
+ return countsOps.getCountsPerPriority(this.ctx);
466
192
  }
193
+ getCountsPerPriorityAsync() {
194
+ return countsOps.getCountsPerPriorityAsync(this.ctx);
195
+ }
196
+ // ============ Control Operations ============
467
197
  pause() {
468
- if (this.embedded)
469
- getSharedManager().pause(this.name);
470
- else
471
- void this.tcp.send({ cmd: 'Pause', queue: this.name });
198
+ controlOps.pause(this.ctx);
472
199
  }
473
200
  resume() {
474
- if (this.embedded)
475
- getSharedManager().resume(this.name);
476
- else
477
- void this.tcp.send({ cmd: 'Resume', queue: this.name });
201
+ controlOps.resume(this.ctx);
478
202
  }
479
203
  drain() {
480
- if (this.embedded)
481
- getSharedManager().drain(this.name);
482
- else
483
- void this.tcp.send({ cmd: 'Drain', queue: this.name });
204
+ controlOps.drain(this.ctx);
484
205
  }
485
206
  obliterate() {
486
- if (this.embedded)
487
- getSharedManager().obliterate(this.name);
488
- else
489
- void this.tcp.send({ cmd: 'Obliterate', queue: this.name });
207
+ controlOps.obliterate(this.ctx);
490
208
  }
491
- /** Check if queue is paused */
492
209
  isPaused() {
493
- if (this.embedded) {
494
- return getSharedManager().isPaused(this.name);
495
- }
496
- return false;
497
- }
498
- /** Check if queue is paused (async, works with TCP) */
499
- async isPausedAsync() {
500
- if (this.embedded)
501
- return this.isPaused();
502
- const response = await this.tcp.send({ cmd: 'IsPaused', queue: this.name });
503
- if (!response.ok)
504
- return false;
505
- return response.paused === true;
506
- }
507
- /** Count jobs awaiting processing */
508
- count() {
509
- if (this.embedded) {
510
- return getSharedManager().count(this.name);
511
- }
512
- return 0;
513
- }
514
- /** Count jobs awaiting processing (async, works with TCP) */
515
- async countAsync() {
516
- if (this.embedded)
517
- return this.count();
518
- const response = await this.tcp.send({ cmd: 'Count', queue: this.name });
519
- if (!response.ok)
520
- return 0;
521
- return response.count ?? 0;
522
- }
523
- /** Get active jobs */
524
- getActive(start = 0, end = 100) {
525
- return this.getJobs({ state: 'active', start, end });
526
- }
527
- /** Get active jobs (async) */
528
- async getActiveAsync(start = 0, end = 100) {
529
- return this.getJobsAsync({ state: 'active', start, end });
530
- }
531
- /** Get completed jobs */
532
- getCompleted(start = 0, end = 100) {
533
- return this.getJobs({ state: 'completed', start, end });
534
- }
535
- /** Get completed jobs (async) */
536
- async getCompletedAsync(start = 0, end = 100) {
537
- return this.getJobsAsync({ state: 'completed', start, end });
538
- }
539
- /** Get failed jobs */
540
- getFailed(start = 0, end = 100) {
541
- return this.getJobs({ state: 'failed', start, end });
542
- }
543
- /** Get failed jobs (async) */
544
- async getFailedAsync(start = 0, end = 100) {
545
- return this.getJobsAsync({ state: 'failed', start, end });
546
- }
547
- /** Get delayed jobs */
548
- getDelayed(start = 0, end = 100) {
549
- return this.getJobs({ state: 'delayed', start, end });
550
- }
551
- /** Get delayed jobs (async) */
552
- async getDelayedAsync(start = 0, end = 100) {
553
- return this.getJobsAsync({ state: 'delayed', start, end });
554
- }
555
- /** Get waiting jobs */
556
- getWaiting(start = 0, end = 100) {
557
- return this.getJobs({ state: 'waiting', start, end });
558
- }
559
- /** Get waiting jobs (async) */
560
- async getWaitingAsync(start = 0, end = 100) {
561
- return this.getJobsAsync({ state: 'waiting', start, end });
562
- }
563
- /** Get active job count */
564
- async getActiveCount() {
565
- const counts = await this.getJobCountsAsync();
566
- return counts.active;
567
- }
568
- /** Get completed job count */
569
- async getCompletedCount() {
570
- const counts = await this.getJobCountsAsync();
571
- return counts.completed;
572
- }
573
- /** Get failed job count */
574
- async getFailedCount() {
575
- const counts = await this.getJobCountsAsync();
576
- return counts.failed;
577
- }
578
- /** Get delayed job count */
579
- async getDelayedCount() {
580
- if (this.embedded) {
581
- const stats = getSharedManager().getStats();
582
- return stats.delayed;
583
- }
584
- const response = await this.tcp.send({ cmd: 'Stats' });
585
- if (!response.ok)
586
- return 0;
587
- return response.stats?.delayed ?? 0;
210
+ return controlOps.isPaused(this.ctx);
211
+ }
212
+ isPausedAsync() {
213
+ return controlOps.isPausedAsync(this.ctx);
588
214
  }
589
- /** Get waiting job count */
590
- async getWaitingCount() {
591
- const counts = await this.getJobCountsAsync();
592
- return counts.waiting;
215
+ waitUntilReady() {
216
+ return controlOps.waitUntilReady(this.ctx);
217
+ }
218
+ // ============ Management Operations ============
219
+ remove(id) {
220
+ managementOps.remove(this.ctx, id);
221
+ }
222
+ removeAsync(id) {
223
+ return managementOps.removeAsync(this.ctx, id);
224
+ }
225
+ retryJob(id) {
226
+ return managementOps.retryJob(this.ctx, id);
227
+ }
228
+ retryJobs(opts) {
229
+ return managementOps.retryJobs(this.ctx, opts);
593
230
  }
594
- /** Clean old jobs from the queue */
595
231
  clean(grace, limit, type) {
596
- if (this.embedded) {
597
- const count = getSharedManager().clean(this.name, grace, type, limit);
598
- // Return empty array for now - would need to track removed IDs
599
- return new Array(count).fill('');
600
- }
601
- return [];
602
- }
603
- /** Clean old jobs from the queue (async, works with TCP) */
604
- async cleanAsync(grace, limit, type) {
605
- if (this.embedded)
606
- return this.clean(grace, limit, type);
607
- const response = await this.tcp.send({
608
- cmd: 'Clean',
609
- queue: this.name,
610
- grace,
611
- limit,
612
- type,
613
- });
614
- if (!response.ok)
615
- return [];
616
- return response.removed ?? [];
617
- }
618
- /** Retry failed jobs */
619
- async retryJobs(opts) {
620
- const state = opts?.state ?? 'failed';
621
- const count = opts?.count ?? 100;
622
- if (this.embedded) {
623
- if (state === 'failed') {
624
- return getSharedManager().retryDlq(this.name);
625
- }
626
- else {
627
- return getSharedManager().retryCompleted(this.name);
628
- }
629
- }
630
- const cmd = state === 'failed' ? 'RetryDlq' : 'RetryCompleted';
631
- const response = await this.tcp.send({ cmd, queue: this.name, count });
632
- if (!response.ok)
633
- return 0;
634
- return response.count ?? 0;
635
- }
636
- /** Promote delayed jobs to waiting */
637
- async promoteJobs(opts) {
638
- const count = opts?.count ?? 100;
639
- if (this.embedded) {
640
- // Get delayed jobs and promote them
641
- const jobs = this.getJobs({ state: 'delayed', start: 0, end: count });
642
- let promoted = 0;
643
- for (const job of jobs) {
644
- const success = await getSharedManager().promote(jobId(job.id));
645
- if (success)
646
- promoted++;
647
- }
648
- return promoted;
649
- }
650
- const response = await this.tcp.send({ cmd: 'PromoteJobs', queue: this.name, count });
651
- if (!response.ok)
652
- return 0;
653
- return response.count ?? 0;
232
+ return managementOps.clean(this.ctx, grace, limit, type);
654
233
  }
655
- /** Get job logs */
656
- async getJobLogs(id, start = 0, end = 100, _asc = true) {
657
- if (this.embedded) {
658
- const logs = getSharedManager().getLogs(jobId(id));
659
- const logStrings = logs.slice(start, end).map((l) => `[${l.level}] ${l.message}`);
660
- return { logs: logStrings, count: logs.length };
661
- }
662
- const response = await this.tcp.send({ cmd: 'GetLogs', id, start, end });
663
- if (!response.ok)
664
- return { logs: [], count: 0 };
665
- const result = response;
666
- const logStrings = (result.logs ?? []).map((l) => `[${l.level}] ${l.message}`);
667
- return { logs: logStrings, count: result.count ?? 0 };
668
- }
669
- /** Add a log entry to a job */
670
- async addJobLog(id, logRow, _keepLogs) {
671
- if (this.embedded) {
672
- const success = getSharedManager().addLog(jobId(id), logRow);
673
- return success ? 1 : 0;
674
- }
675
- const response = await this.tcp.send({ cmd: 'AddLog', id, message: logRow });
676
- return response.ok ? 1 : 0;
234
+ cleanAsync(grace, limit, type) {
235
+ return managementOps.cleanAsync(this.ctx, grace, limit, type);
677
236
  }
678
- /** Update job progress */
679
- async updateJobProgress(id, progress) {
680
- const progressValue = typeof progress === 'number' ? progress : 0;
681
- const message = typeof progress === 'object' ? JSON.stringify(progress) : undefined;
682
- if (this.embedded) {
683
- await getSharedManager().updateProgress(jobId(id), progressValue, message);
684
- return;
685
- }
686
- await this.tcp.send({ cmd: 'Progress', id, progress: progressValue, message });
237
+ promoteJobs(opts) {
238
+ return managementOps.promoteJobs(this.ctx, opts);
687
239
  }
688
- /** Set global concurrency limit for this queue */
689
- setGlobalConcurrency(concurrency) {
690
- if (this.embedded) {
691
- getSharedManager().setConcurrency(this.name, concurrency);
692
- }
693
- else {
694
- void this.tcp.send({ cmd: 'SetConcurrency', queue: this.name, limit: concurrency });
695
- }
240
+ promoteJob(id) {
241
+ return managementOps.promoteJob(this.ctx, id);
696
242
  }
697
- /** Remove global concurrency limit */
698
- removeGlobalConcurrency() {
699
- if (this.embedded) {
700
- getSharedManager().clearConcurrency(this.name);
701
- }
702
- else {
703
- void this.tcp.send({ cmd: 'ClearConcurrency', queue: this.name });
704
- }
243
+ updateJobProgress(id, progress) {
244
+ return managementOps.updateJobProgress(this.ctx, id, progress);
705
245
  }
706
- /** Get global concurrency limit */
707
- getGlobalConcurrency() {
708
- // This would need to be implemented in QueueManager
709
- // For now, return null
710
- return Promise.resolve(null);
246
+ getJobLogs(id, start, end, _asc) {
247
+ return managementOps.getJobLogs(this.ctx, id, start, end);
711
248
  }
712
- /** Set global rate limit for this queue */
713
- setGlobalRateLimit(max, _duration) {
714
- if (this.embedded) {
715
- getSharedManager().setRateLimit(this.name, max);
716
- }
717
- else {
718
- void this.tcp.send({ cmd: 'RateLimit', queue: this.name, limit: max });
719
- }
249
+ addJobLog(id, logRow, _keepLogs) {
250
+ return managementOps.addJobLog(this.ctx, id, logRow);
720
251
  }
721
- /** Remove global rate limit */
722
- removeGlobalRateLimit() {
723
- if (this.embedded) {
724
- getSharedManager().clearRateLimit(this.name);
725
- }
726
- else {
727
- void this.tcp.send({ cmd: 'RateLimitClear', queue: this.name });
728
- }
252
+ clearJobLogs(id, keepLogs) {
253
+ return managementOps.clearJobLogs(this.ctx, id, keepLogs);
729
254
  }
730
- /** Get global rate limit */
731
- getGlobalRateLimit() {
732
- // This would need to be implemented in QueueManager
733
- // For now, return null
734
- return Promise.resolve(null);
255
+ updateJobData(id, data) {
256
+ return managementOps.updateJobData(this.ctx, id, data);
735
257
  }
736
- /** Get metrics for this queue */
737
- async getMetrics(type, _start, _end) {
738
- if (this.embedded) {
739
- const stats = getSharedManager().getStats();
740
- const count = type === 'completed' ? stats.completed : stats.dlq;
741
- return { meta: { count }, data: [] };
742
- }
743
- const response = await this.tcp.send({ cmd: 'Metrics' });
744
- if (!response.ok)
745
- return { meta: { count: 0 }, data: [] };
746
- const stats = response.stats;
747
- const count = type === 'completed' ? (stats?.completed ?? 0) : (stats?.dlq ?? 0);
748
- return { meta: { count }, data: [] };
749
- }
750
- /** Get workers processing this queue */
751
- async getWorkers() {
752
- if (this.embedded) {
753
- // Would need to implement worker tracking
754
- return [];
755
- }
756
- const response = await this.tcp.send({ cmd: 'ListWorkers' });
757
- if (!response.ok)
758
- return [];
759
- return (response.workers ?? []);
760
- }
761
- /** Get worker count */
762
- async getWorkersCount() {
763
- const workers = await this.getWorkers();
764
- return workers.length;
765
- }
766
- /** Get jobs with filtering and pagination */
767
- getJobs(options = {}) {
768
- if (this.embedded) {
769
- const jobs = getSharedManager().getJobs(this.name, options);
770
- return jobs.map((job) => {
771
- const jobData = job.data;
772
- return toPublicJob({
773
- job,
774
- name: jobData?.name ?? 'default',
775
- getState: (jid) => this.getJobState(jid),
776
- remove: (jid) => this.removeAsync(jid),
777
- retry: (jid) => this.retryJob(jid),
778
- getChildrenValues: (jid) => this.getChildrenValues(jid),
779
- updateData: (jid, data) => this.updateJobData(jid, data),
780
- promote: (jid) => this.promoteJob(jid),
781
- changeDelay: (jid, delay) => this.changeJobDelay(jid, delay),
782
- changePriority: (jid, opts) => this.changeJobPriority(jid, opts),
783
- extendLock: (jid, token, duration) => this.extendJobLock(jid, token, duration),
784
- clearLogs: (jid, keepLogs) => this.clearJobLogs(jid, keepLogs),
785
- getDependencies: (jid, opts) => this.getJobDependencies(jid, opts),
786
- getDependenciesCount: (jid, opts) => this.getJobDependenciesCount(jid, opts),
787
- moveToCompleted: (jid, result, token) => this.moveJobToCompleted(jid, result, token),
788
- moveToFailed: (jid, error, token) => this.moveJobToFailed(jid, error, token),
789
- moveToWait: (jid, token) => this.moveJobToWait(jid, token),
790
- moveToDelayed: (jid, timestamp, token) => this.moveJobToDelayed(jid, timestamp, token),
791
- moveToWaitingChildren: (jid, token, opts) => this.moveJobToWaitingChildren(jid, token, opts),
792
- waitUntilFinished: (jid, queueEvents, ttl) => this.waitJobUntilFinished(jid, queueEvents, ttl),
793
- });
794
- });
795
- }
796
- // Sync TCP version returns empty - use getJobsAsync
797
- return [];
798
- }
799
- /** Get jobs with filtering and pagination (async, works with TCP) */
800
- async getJobsAsync(options = {}) {
801
- if (this.embedded)
802
- return this.getJobs(options);
803
- const response = await this.tcp.send({
804
- cmd: 'GetJobs',
805
- queue: this.name,
806
- state: options.state,
807
- offset: options.start ?? 0,
808
- limit: (options.end ?? 100) - (options.start ?? 0),
809
- });
810
- if (!response.ok || !Array.isArray(response.jobs)) {
811
- return [];
812
- }
813
- const jobs = response.jobs;
814
- return jobs.map((j) => {
815
- const jobData = j.data;
816
- const jobName = jobData?.name ?? 'default';
817
- return {
818
- id: j.id,
819
- name: jobName,
820
- data: j.data,
821
- queueName: j.queue,
822
- attemptsMade: j.attempts,
823
- timestamp: j.createdAt,
824
- progress: j.progress ?? 0,
825
- // BullMQ v5 properties
826
- delay: 0,
827
- processedOn: undefined,
828
- finishedOn: undefined,
829
- stacktrace: null,
830
- stalledCounter: 0,
831
- priority: j.priority,
832
- parentKey: undefined,
833
- opts: {},
834
- token: undefined,
835
- processedBy: undefined,
836
- deduplicationId: undefined,
837
- repeatJobKey: undefined,
838
- attemptsStarted: j.attempts,
839
- // Methods
840
- updateProgress: async () => { },
841
- log: async () => { },
842
- getState: () => this.getJobState(j.id),
843
- remove: () => this.removeAsync(j.id),
844
- retry: () => this.retryJob(j.id),
845
- getChildrenValues: () => this.getChildrenValues(j.id),
846
- // BullMQ v5 state check methods
847
- isWaiting: async () => (await this.getJobState(j.id)) === 'waiting',
848
- isActive: async () => (await this.getJobState(j.id)) === 'active',
849
- isDelayed: async () => (await this.getJobState(j.id)) === 'delayed',
850
- isCompleted: async () => (await this.getJobState(j.id)) === 'completed',
851
- isFailed: async () => (await this.getJobState(j.id)) === 'failed',
852
- isWaitingChildren: () => Promise.resolve(false),
853
- // BullMQ v5 mutation methods
854
- updateData: async () => { },
855
- promote: async () => { },
856
- changeDelay: async () => { },
857
- changePriority: async () => { },
858
- extendLock: () => Promise.resolve(0),
859
- clearLogs: async () => { },
860
- // BullMQ v5 dependency methods
861
- getDependencies: () => Promise.resolve({ processed: {}, unprocessed: [] }),
862
- getDependenciesCount: () => Promise.resolve({ processed: 0, unprocessed: 0 }),
863
- // BullMQ v5 serialization methods
864
- toJSON: () => ({
865
- id: j.id,
866
- name: jobName,
867
- data: j.data,
868
- opts: {},
869
- progress: j.progress ?? 0,
870
- delay: 0,
871
- timestamp: j.createdAt,
872
- attemptsMade: j.attempts,
873
- stacktrace: null,
874
- queueQualifiedName: `bull:${j.queue}`,
875
- }),
876
- asJSON: () => ({
877
- id: j.id,
878
- name: jobName,
879
- data: JSON.stringify(j.data),
880
- opts: '{}',
881
- progress: String(j.progress ?? 0),
882
- delay: '0',
883
- timestamp: String(j.createdAt),
884
- attemptsMade: String(j.attempts),
885
- stacktrace: null,
886
- }),
887
- // BullMQ v5 move methods
888
- moveToCompleted: () => Promise.resolve(null),
889
- moveToFailed: () => Promise.resolve(),
890
- moveToWait: () => Promise.resolve(false),
891
- moveToDelayed: () => Promise.resolve(),
892
- moveToWaitingChildren: () => Promise.resolve(false),
893
- waitUntilFinished: () => Promise.resolve(undefined),
894
- // BullMQ v5 additional methods
895
- discard: () => { },
896
- getFailedChildrenValues: () => Promise.resolve({}),
897
- getIgnoredChildrenFailures: () => Promise.resolve({}),
898
- removeChildDependency: () => Promise.resolve(false),
899
- removeDeduplicationKey: () => Promise.resolve(false),
900
- removeUnprocessedChildren: () => Promise.resolve(),
901
- };
902
- });
258
+ changeJobDelay(id, delay) {
259
+ return managementOps.changeJobDelay(this.ctx, id, delay);
260
+ }
261
+ changeJobPriority(id, opts) {
262
+ return managementOps.changeJobPriority(this.ctx, id, opts);
903
263
  }
904
- // Stall Detection
264
+ extendJobLock(id, token, duration) {
265
+ return managementOps.extendJobLock(this.ctx, id, token, duration);
266
+ }
267
+ // ============ Stall Detection ============
905
268
  setStallConfig(config) {
906
- if (!this.embedded) {
907
- console.warn('setStallConfig: embedded only');
908
- return;
909
- }
910
- dlqOps.setStallConfigEmbedded(this.name, config);
269
+ stallOps.setStallConfig(this.ctx, config);
911
270
  }
912
271
  getStallConfig() {
913
- if (!this.embedded) {
914
- return { enabled: true, stallInterval: 30000, maxStalls: 3, gracePeriod: 5000 };
915
- }
916
- return dlqOps.getStallConfigEmbedded(this.name);
272
+ return stallOps.getStallConfig(this.ctx);
917
273
  }
918
- // DLQ Operations
274
+ // ============ DLQ Operations ============
919
275
  setDlqConfig(config) {
920
- if (!this.embedded) {
921
- console.warn('setDlqConfig: embedded only');
922
- return;
923
- }
924
- dlqOps.setDlqConfig(this.name, config);
276
+ dlqOps.setDlqConfig(this.ctx, config);
925
277
  }
926
278
  getDlqConfig() {
927
- if (!this.embedded)
928
- return {};
929
- return dlqOps.getDlqConfigEmbedded(this.name);
279
+ return dlqOps.getDlqConfig(this.ctx);
930
280
  }
931
281
  getDlq(filter) {
932
- if (!this.embedded)
933
- return [];
934
- return dlqOps.getDlqEntries(this.name, filter);
282
+ return dlqOps.getDlq(this.ctx, filter);
935
283
  }
936
284
  getDlqStats() {
937
- if (!this.embedded) {
938
- return {
939
- total: 0,
940
- byReason: {},
941
- pendingRetry: 0,
942
- expired: 0,
943
- oldestEntry: null,
944
- newestEntry: null,
945
- };
946
- }
947
- return dlqOps.getDlqStatsEmbedded(this.name);
285
+ return dlqOps.getDlqStats(this.ctx);
948
286
  }
949
287
  retryDlq(id) {
950
- if (this.embedded)
951
- return dlqOps.retryDlqEmbedded(this.name, id);
952
- void this.tcp.send({ cmd: 'RetryDlq', queue: this.name, id });
953
- return 0;
288
+ return dlqOps.retryDlq(this.ctx, id);
954
289
  }
955
290
  retryDlqByFilter(filter) {
956
- if (!this.embedded)
957
- return 0;
958
- return dlqOps.retryDlqByFilterEmbedded(this.name, filter);
291
+ return dlqOps.retryDlqByFilter(this.ctx, filter);
959
292
  }
960
293
  purgeDlq() {
961
- if (this.embedded)
962
- return dlqOps.purgeDlqEmbedded(this.name);
963
- void this.tcp.send({ cmd: 'PurgeDlq', queue: this.name });
964
- return 0;
294
+ return dlqOps.purgeDlq(this.ctx);
965
295
  }
966
- /** Retry a completed job by re-queueing it */
967
296
  retryCompleted(id) {
968
- if (this.embedded) {
969
- const jid = id ? jobId(id) : undefined;
970
- return getSharedManager().retryCompleted(this.name, jid);
971
- }
972
- void this.tcp.send({ cmd: 'RetryCompleted', queue: this.name, id });
973
- return 0;
974
- }
975
- /** Retry a completed job (async, works with TCP) */
976
- async retryCompletedAsync(id) {
977
- if (this.embedded)
978
- return this.retryCompleted(id);
979
- const response = await this.tcp.send({ cmd: 'RetryCompleted', queue: this.name, id });
980
- if (!response.ok)
981
- return 0;
982
- return response.count ?? 0;
983
- }
984
- // ============================================================================
985
- // BullMQ v5 Compatibility Methods (Additional)
986
- // ============================================================================
987
- /**
988
- * Trim events to a maximum length.
989
- * In bunqueue, events are emitted in real-time and not stored, so this is a no-op.
990
- */
991
- trimEvents(_maxLength) {
992
- // Events in bunqueue are not persisted - they're emitted via EventEmitter
993
- return Promise.resolve(0);
994
- }
995
- /**
996
- * Get jobs sorted by priority (highest first).
997
- * In BullMQ, this returns jobs waiting to be processed sorted by priority.
998
- */
999
- getPrioritized(start = 0, end = -1) {
1000
- // In bunqueue, all waiting jobs are already prioritized in the priority queue
1001
- return this.getWaitingAsync(start, end);
1002
- }
1003
- /** Get count of prioritized jobs (same as waiting count in bunqueue) */
1004
- getPrioritizedCount() {
1005
- return this.getWaitingCount();
297
+ return dlqOps.retryCompleted(this.ctx, id);
1006
298
  }
1007
- /**
1008
- * Get jobs that are waiting for their parent to complete.
1009
- * Used in job flows (parent-child dependencies).
1010
- */
1011
- getWaitingChildren(start = 0, end = -1) {
1012
- if (this.embedded) {
1013
- // Get jobs with pending dependencies
1014
- const jobs = getSharedManager().getJobs(this.name, {
1015
- state: 'delayed',
1016
- start,
1017
- end: end === -1 ? 1000 : end,
1018
- });
1019
- // Filter to only those with dependencies (would need dependency tracking)
1020
- const result = jobs
1021
- .filter((j) => {
1022
- const data = j.data;
1023
- return data?._waitingParent === true;
1024
- })
1025
- .map((job) => {
1026
- const jobData = job.data;
1027
- return toPublicJob({
1028
- job,
1029
- name: jobData?.name ?? 'default',
1030
- getState: (jid) => this.getJobState(jid),
1031
- remove: (jid) => this.removeAsync(jid),
1032
- retry: (jid) => this.retryJob(jid),
1033
- getChildrenValues: (jid) => this.getChildrenValues(jid),
1034
- updateData: (jid, data) => this.updateJobData(jid, data),
1035
- promote: (jid) => this.promoteJob(jid),
1036
- changeDelay: (jid, delay) => this.changeJobDelay(jid, delay),
1037
- changePriority: (jid, opts) => this.changeJobPriority(jid, opts),
1038
- extendLock: (jid, token, duration) => this.extendJobLock(jid, token, duration),
1039
- clearLogs: (jid, keepLogs) => this.clearJobLogs(jid, keepLogs),
1040
- getDependencies: (jid, opts) => this.getJobDependencies(jid, opts),
1041
- getDependenciesCount: (jid, opts) => this.getJobDependenciesCount(jid, opts),
1042
- });
1043
- });
1044
- return Promise.resolve(result);
1045
- }
1046
- // TCP mode - not fully supported yet
1047
- return Promise.resolve([]);
1048
- }
1049
- /** Get count of jobs waiting for their parent */
1050
- async getWaitingChildrenCount() {
1051
- const children = await this.getWaitingChildren();
1052
- return children.length;
1053
- }
1054
- /**
1055
- * Get dependencies of a parent job.
1056
- * Returns processed/unprocessed children of a parent job in a flow.
1057
- */
1058
- getDependencies(_parentId, _type, _start = 0, _end = -1) {
1059
- // Would require implementing dependency tracking
1060
- return Promise.resolve({
1061
- processed: {},
1062
- unprocessed: [],
1063
- });
299
+ retryCompletedAsync(id) {
300
+ return dlqOps.retryCompletedAsync(this.ctx, id);
1064
301
  }
1065
- /**
1066
- * Get the TTL of the current rate limit.
1067
- * Returns 0 if no rate limit is active.
1068
- */
1069
- getRateLimitTtl(_maxJobs) {
1070
- // Would need to track rate limit expiration
1071
- return Promise.resolve(0);
1072
- }
1073
- /**
1074
- * Set a temporary rate limit that expires after the given time.
1075
- */
1076
- async rateLimit(expireTimeMs) {
1077
- if (this.embedded) {
1078
- // Set rate limit with expiration
1079
- getSharedManager().setRateLimit(this.name, 1);
1080
- // Schedule removal after expiration
1081
- setTimeout(() => {
1082
- getSharedManager().clearRateLimit(this.name);
1083
- }, expireTimeMs);
1084
- }
1085
- else {
1086
- await this.tcp.send({ cmd: 'RateLimit', queue: this.name, limit: 1 });
1087
- // Note: TCP mode would need server-side expiration support
1088
- }
302
+ // ============ Rate Limit Operations ============
303
+ setGlobalConcurrency(concurrency) {
304
+ rateLimitOps.setGlobalConcurrency(this.ctx, concurrency);
305
+ }
306
+ removeGlobalConcurrency() {
307
+ rateLimitOps.removeGlobalConcurrency(this.ctx);
308
+ }
309
+ getGlobalConcurrency() {
310
+ return rateLimitOps.getGlobalConcurrency(this.ctx);
311
+ }
312
+ setGlobalRateLimit(max, duration) {
313
+ rateLimitOps.setGlobalRateLimit(this.ctx, max, duration);
314
+ }
315
+ removeGlobalRateLimit() {
316
+ rateLimitOps.removeGlobalRateLimit(this.ctx);
317
+ }
318
+ getGlobalRateLimit() {
319
+ return rateLimitOps.getGlobalRateLimit(this.ctx);
320
+ }
321
+ rateLimit(expireTimeMs) {
322
+ return rateLimitOps.rateLimit(this.ctx, expireTimeMs);
323
+ }
324
+ getRateLimitTtl(maxJobs) {
325
+ return rateLimitOps.getRateLimitTtl(this.ctx, maxJobs);
1089
326
  }
1090
- /**
1091
- * Check if the queue is currently rate limited (at max capacity).
1092
- */
1093
327
  isMaxed() {
1094
- // Would need to check if rate limit is currently blocking
1095
- return Promise.resolve(false);
1096
- }
1097
- // ============================================================================
1098
- // Job Scheduler Methods (BullMQ v5 repeatable jobs)
1099
- // ============================================================================
1100
- /**
1101
- * Create or update a job scheduler (repeatable job).
1102
- * This is the BullMQ v5 way to handle cron/repeating jobs.
1103
- */
1104
- async upsertJobScheduler(schedulerId, repeatOpts, jobTemplate) {
1105
- const cronPattern = repeatOpts.pattern;
1106
- const repeatEvery = repeatOpts.every;
1107
- if (this.embedded) {
1108
- const manager = getSharedManager();
1109
- // Use the cron scheduler
1110
- manager.addCron({
1111
- name: schedulerId,
1112
- queue: this.name,
1113
- data: jobTemplate?.data ?? {},
1114
- schedule: cronPattern,
1115
- repeatEvery,
1116
- timezone: 'UTC',
1117
- });
1118
- return {
1119
- id: schedulerId,
1120
- name: jobTemplate?.name ?? 'default',
1121
- next: Date.now() + (repeatEvery ?? 60000),
1122
- };
1123
- }
1124
- else {
1125
- const response = await this.tcp.send({
1126
- cmd: 'Cron',
1127
- name: schedulerId,
1128
- queue: this.name,
1129
- data: jobTemplate?.data ?? {},
1130
- schedule: cronPattern,
1131
- repeatEvery,
1132
- });
1133
- if (!response.ok)
1134
- return null;
1135
- return {
1136
- id: schedulerId,
1137
- name: jobTemplate?.name ?? 'default',
1138
- next: response.nextRun ?? Date.now(),
1139
- };
1140
- }
328
+ return rateLimitOps.isMaxed(this.ctx);
1141
329
  }
1142
- /**
1143
- * Remove a job scheduler.
1144
- */
1145
- async removeJobScheduler(schedulerId) {
1146
- if (this.embedded) {
1147
- getSharedManager().removeCron(schedulerId);
1148
- return true;
1149
- }
1150
- else {
1151
- const response = await this.tcp.send({ cmd: 'CronDelete', name: schedulerId });
1152
- return response.ok === true;
1153
- }
330
+ // ============ Scheduler Operations ============
331
+ upsertJobScheduler(schedulerId, repeatOpts, jobTemplate) {
332
+ return schedulerOps.upsertJobScheduler(this.ctx, schedulerId, repeatOpts, jobTemplate);
1154
333
  }
1155
- /**
1156
- * Get a job scheduler by ID.
1157
- */
1158
- async getJobScheduler(schedulerId) {
1159
- if (this.embedded) {
1160
- const crons = getSharedManager().listCrons();
1161
- const cron = crons.find((c) => c.name === schedulerId);
1162
- if (!cron)
1163
- return null;
1164
- return {
1165
- id: cron.name,
1166
- name: cron.name,
1167
- next: cron.nextRun,
1168
- pattern: cron.schedule ?? undefined,
1169
- every: cron.repeatEvery ?? undefined,
1170
- };
1171
- }
1172
- else {
1173
- const response = await this.tcp.send({ cmd: 'CronList' });
1174
- if (!response.ok)
1175
- return null;
1176
- const crons = response.crons;
1177
- const cron = crons?.find((c) => c.name === schedulerId);
1178
- if (!cron)
1179
- return null;
1180
- return {
1181
- id: cron.name,
1182
- name: cron.name,
1183
- next: cron.nextRun,
1184
- pattern: cron.schedule ?? undefined,
1185
- every: cron.repeatEvery ?? undefined,
1186
- };
1187
- }
334
+ removeJobScheduler(schedulerId) {
335
+ return schedulerOps.removeJobScheduler(this.ctx, schedulerId);
1188
336
  }
1189
- /**
1190
- * Get all job schedulers for this queue.
1191
- */
1192
- async getJobSchedulers(_start = 0, _end = -1, _asc = true) {
1193
- if (this.embedded) {
1194
- const crons = getSharedManager()
1195
- .listCrons()
1196
- .filter((c) => c.queue === this.name);
1197
- return crons.map((c) => ({
1198
- id: c.name,
1199
- name: c.name,
1200
- next: c.nextRun,
1201
- pattern: c.schedule ?? undefined,
1202
- every: c.repeatEvery ?? undefined,
1203
- }));
1204
- }
1205
- else {
1206
- const response = await this.tcp.send({ cmd: 'CronList' });
1207
- if (!response.ok)
1208
- return [];
1209
- const crons = response.crons;
1210
- return (crons ?? [])
1211
- .filter((c) => c.queue === this.name)
1212
- .map((c) => ({
1213
- id: c.name,
1214
- name: c.name,
1215
- next: c.nextRun,
1216
- pattern: c.schedule ?? undefined,
1217
- every: c.repeatEvery ?? undefined,
1218
- }));
1219
- }
337
+ getJobScheduler(schedulerId) {
338
+ return schedulerOps.getJobScheduler(this.ctx, schedulerId);
339
+ }
340
+ getJobSchedulers(start, end, asc) {
341
+ return schedulerOps.getJobSchedulers(this.ctx, start, end, asc);
1220
342
  }
1221
- /** Get count of job schedulers for this queue */
1222
- async getJobSchedulersCount() {
1223
- const schedulers = await this.getJobSchedulers();
1224
- return schedulers.length;
1225
- }
1226
- // ============================================================================
1227
- // Deduplication Methods
1228
- // ============================================================================
1229
- /**
1230
- * Get the job ID associated with a deduplication key.
1231
- */
343
+ getJobSchedulersCount() {
344
+ return schedulerOps.getJobSchedulersCount(this.ctx);
345
+ }
346
+ // ============ Deduplication Operations ============
1232
347
  getDeduplicationJobId(deduplicationId) {
1233
- if (this.embedded) {
1234
- const job = getSharedManager().getJobByCustomId(deduplicationId);
1235
- return Promise.resolve(job ? String(job.id) : null);
1236
- }
1237
- // TCP mode - would need server support
1238
- return Promise.resolve(null);
348
+ return deduplicationOps.getDeduplicationJobId(this.ctx, deduplicationId);
1239
349
  }
1240
- /**
1241
- * Remove a deduplication key, allowing a new job with the same key.
1242
- */
1243
350
  removeDeduplicationKey(deduplicationId) {
1244
- if (this.embedded) {
1245
- // Remove the custom ID mapping
1246
- const job = getSharedManager().getJobByCustomId(deduplicationId);
1247
- if (job) {
1248
- // Would need a method to remove just the customId mapping
1249
- return Promise.resolve(1);
1250
- }
1251
- return Promise.resolve(0);
1252
- }
1253
- return Promise.resolve(0);
1254
- }
1255
- // ============================================================================
1256
- // Connection Methods
1257
- // ============================================================================
1258
- /**
1259
- * Wait until the queue is ready (connection established).
1260
- */
1261
- async waitUntilReady() {
1262
- if (this.embedded) {
1263
- // Embedded mode is always ready
1264
- return;
1265
- }
1266
- // TCP mode - the pool handles connection
1267
- // Just ensure we can send a ping
1268
- await this.tcp.send({ cmd: 'Ping' });
351
+ return deduplicationOps.removeDeduplicationKey(this.ctx, deduplicationId);
1269
352
  }
1270
- /**
1271
- * Disconnect from the server (async version of close).
1272
- */
1273
- disconnect() {
1274
- this.close();
1275
- return Promise.resolve();
353
+ // ============ Job Move Operations ============
354
+ moveJobToCompleted(id, returnValue, token) {
355
+ return jobMoveOps.moveJobToCompleted(this.moveCtx, id, returnValue, token);
1276
356
  }
1277
- // ============================================================================
1278
- // BullMQ v5 Job Mutation Methods (used by Job instances)
1279
- // ============================================================================
1280
- /** Update job data */
1281
- async updateJobData(id, data) {
1282
- if (this.embedded) {
1283
- const manager = getSharedManager();
1284
- await manager.updateJobData(jobId(id), data);
1285
- }
1286
- else {
1287
- await this.tcp.send({ cmd: 'Update', id, data });
1288
- }
357
+ moveJobToFailed(id, error, token) {
358
+ return jobMoveOps.moveJobToFailed(this.moveCtx, id, error, token);
1289
359
  }
1290
- /** Promote a delayed job to waiting */
1291
- async promoteJob(id) {
1292
- if (this.embedded) {
1293
- await getSharedManager().promote(jobId(id));
1294
- }
1295
- else {
1296
- await this.tcp.send({ cmd: 'Promote', id });
1297
- }
360
+ moveJobToWait(id, token) {
361
+ return jobMoveOps.moveJobToWait(this.moveCtx, id, token);
1298
362
  }
1299
- /** Change job delay */
1300
- async changeJobDelay(id, delay) {
1301
- if (this.embedded) {
1302
- const manager = getSharedManager();
1303
- await manager.changeDelay(jobId(id), delay);
1304
- }
1305
- else {
1306
- await this.tcp.send({ cmd: 'ChangeDelay', id, delay });
1307
- }
363
+ moveJobToDelayed(id, timestamp, token) {
364
+ return jobMoveOps.moveJobToDelayed(this.moveCtx, id, timestamp, token);
1308
365
  }
1309
- /** Change job priority */
1310
- async changeJobPriority(id, opts) {
1311
- if (this.embedded) {
1312
- const manager = getSharedManager();
1313
- await manager.changePriority(jobId(id), opts.priority);
1314
- }
1315
- else {
1316
- await this.tcp.send({ cmd: 'ChangePriority', id, priority: opts.priority });
1317
- }
366
+ moveJobToWaitingChildren(id, token, opts) {
367
+ return jobMoveOps.moveJobToWaitingChildren(this.moveCtx, id, token, opts);
1318
368
  }
1319
- /** Extend job lock */
1320
- async extendJobLock(id, token, duration) {
1321
- if (this.embedded) {
1322
- const manager = getSharedManager();
1323
- const extended = await manager.extendLock(jobId(id), token || null, duration);
1324
- return extended ? duration : 0;
1325
- }
1326
- else {
1327
- const response = await this.tcp.send({ cmd: 'ExtendLock', id, token, duration });
1328
- return response.ok ? duration : 0;
1329
- }
369
+ waitJobUntilFinished(id, queueEvents, ttl) {
370
+ return jobMoveOps.waitJobUntilFinished(this.moveCtx, id, queueEvents, ttl);
1330
371
  }
1331
- /** Clear job logs */
1332
- async clearJobLogs(id, keepLogs) {
1333
- if (this.embedded) {
1334
- const manager = getSharedManager();
1335
- manager.clearLogs(jobId(id), keepLogs);
1336
- }
1337
- else {
1338
- await this.tcp.send({ cmd: 'ClearLogs', id, keepLogs });
1339
- }
372
+ // ============ Dependency Operations ============
373
+ getJobDependencies(id, opts) {
374
+ return bullmqCompatOps.getJobDependencies(this.addCtx, id, opts);
1340
375
  }
1341
- /** Get job dependencies */
1342
- async getJobDependencies(id, _opts) {
1343
- if (this.embedded) {
1344
- const manager = getSharedManager();
1345
- const job = await manager.getJob(jobId(id));
1346
- if (!job)
1347
- return { processed: {}, unprocessed: [] };
1348
- const childIds = job.childrenIds;
1349
- const processed = {};
1350
- const unprocessed = [];
1351
- for (const childId of childIds) {
1352
- const result = manager.getResult(childId);
1353
- if (result !== undefined) {
1354
- const childJob = await manager.getJob(childId);
1355
- const key = childJob ? `${childJob.queue}:${childId}` : String(childId);
1356
- processed[key] = result;
1357
- }
1358
- else {
1359
- unprocessed.push(String(childId));
1360
- }
1361
- }
1362
- return { processed, unprocessed };
1363
- }
1364
- // TCP mode
1365
- return { processed: {}, unprocessed: [] };
376
+ getJobDependenciesCount(id, opts) {
377
+ return bullmqCompatOps.getJobDependenciesCount(this.addCtx, id, opts);
1366
378
  }
1367
- /** Get job dependencies count */
1368
- async getJobDependenciesCount(id, _opts) {
1369
- if (this.embedded) {
1370
- const deps = await this.getJobDependencies(id);
1371
- return {
1372
- processed: Object.keys(deps.processed).length,
1373
- unprocessed: deps.unprocessed.length,
1374
- };
1375
- }
1376
- return { processed: 0, unprocessed: 0 };
1377
- }
1378
- // ============================================================================
1379
- // BullMQ v5 Job Move Methods
1380
- // ============================================================================
1381
- /**
1382
- * Move job to completed state (BullMQ v5 compatible).
1383
- * Used internally by workers to mark jobs as complete.
1384
- */
1385
- async moveJobToCompleted(id, returnValue, _token) {
1386
- if (this.embedded) {
1387
- const manager = getSharedManager();
1388
- await manager.ack(jobId(id), returnValue);
1389
- return null; // Could return next job if fetchNext was true
1390
- }
1391
- else {
1392
- await this.tcp.send({ cmd: 'ACK', id, result: returnValue });
1393
- return null;
1394
- }
379
+ getDependencies(parentId, type, start, end) {
380
+ return bullmqCompatOps.getDependencies(this.addCtx, parentId, type, start, end);
1395
381
  }
1396
- /**
1397
- * Move job to failed state (BullMQ v5 compatible).
1398
- * Used internally by workers to mark jobs as failed.
1399
- */
1400
- async moveJobToFailed(id, error, _token) {
1401
- if (this.embedded) {
1402
- const manager = getSharedManager();
1403
- await manager.fail(jobId(id), error.message);
1404
- }
1405
- else {
1406
- await this.tcp.send({ cmd: 'FAIL', id, error: error.message });
1407
- }
382
+ // ============ BullMQ Compatibility ============
383
+ getPrioritized(start, end) {
384
+ return bullmqCompatOps.getPrioritized({
385
+ ...this.addCtx,
386
+ getWaitingAsync: (s, e) => this.getWaitingAsync(s, e),
387
+ }, start, end);
1408
388
  }
1409
- /**
1410
- * Move job back to waiting state (BullMQ v5 compatible).
1411
- * Useful for re-queueing a job that needs to be processed again.
1412
- */
1413
- async moveJobToWait(id, _token) {
1414
- if (this.embedded) {
1415
- const manager = getSharedManager();
1416
- const job = await manager.getJob(jobId(id));
1417
- if (!job)
1418
- return false;
1419
- // Re-queue the job by pushing it again
1420
- await manager.push(job.queue, {
1421
- data: job.data,
1422
- priority: job.priority,
1423
- customId: job.customId ?? undefined,
1424
- });
1425
- return true;
1426
- }
1427
- else {
1428
- const response = await this.tcp.send({ cmd: 'MoveToWait', id });
1429
- return response.ok === true;
1430
- }
389
+ getPrioritizedCount() {
390
+ return bullmqCompatOps.getPrioritizedCount({
391
+ ...this.addCtx,
392
+ getWaitingAsync: (s, e) => this.getWaitingAsync(s, e),
393
+ });
1431
394
  }
1432
- /**
1433
- * Move job to delayed state (BullMQ v5 compatible).
1434
- * The job will become available for processing at the specified timestamp.
1435
- */
1436
- async moveJobToDelayed(id, timestamp, _token) {
1437
- if (this.embedded) {
1438
- const manager = getSharedManager();
1439
- const delay = Math.max(0, timestamp - Date.now());
1440
- await manager.changeDelay(jobId(id), delay);
1441
- }
1442
- else {
1443
- await this.tcp.send({ cmd: 'MoveToDelayed', id, timestamp });
1444
- }
395
+ getWaitingChildren(start, end) {
396
+ return bullmqCompatOps.getWaitingChildren(this.addCtx, start, end);
1445
397
  }
1446
- /**
1447
- * Move job to waiting-children state (BullMQ v5 compatible).
1448
- * Job will wait for all children to complete before processing.
1449
- */
1450
- async moveJobToWaitingChildren(id, _token, _opts) {
1451
- if (this.embedded) {
1452
- // In embedded mode, this is handled automatically by the dependency system
1453
- // The job is already in waiting-children state if it has pending children
1454
- const manager = getSharedManager();
1455
- const job = await manager.getJob(jobId(id));
1456
- if (!job)
1457
- return false;
1458
- // Check if job has unprocessed children
1459
- const deps = await this.getJobDependencies(id);
1460
- return deps.unprocessed.length > 0;
1461
- }
1462
- return false;
1463
- }
1464
- /**
1465
- * Wait until job has finished (completed or failed).
1466
- * BullMQ v5 compatible method.
1467
- */
1468
- async waitJobUntilFinished(id, queueEvents, ttl) {
1469
- return new Promise((resolve, reject) => {
1470
- const timeout = ttl
1471
- ? setTimeout(() => {
1472
- cleanup();
1473
- reject(new Error(`Job ${id} timed out after ${ttl}ms`));
1474
- }, ttl)
1475
- : null;
1476
- // Cast queueEvents to expected interface
1477
- const events = queueEvents;
1478
- const completedHandler = (data) => {
1479
- if (data.jobId === id) {
1480
- cleanup();
1481
- resolve(data.returnvalue);
1482
- }
1483
- };
1484
- const failedHandler = (data) => {
1485
- if (data.jobId === id) {
1486
- cleanup();
1487
- reject(new Error(data.failedReason ?? 'Job failed'));
1488
- }
1489
- };
1490
- const cleanup = () => {
1491
- if (timeout)
1492
- clearTimeout(timeout);
1493
- events.off('completed', completedHandler);
1494
- events.off('failed', failedHandler);
1495
- };
1496
- events.on('completed', completedHandler);
1497
- events.on('failed', failedHandler);
1498
- // Also check if job is already finished
1499
- void this.getJobState(id).then((state) => {
1500
- if (state === 'completed') {
1501
- cleanup();
1502
- // Get the result
1503
- if (this.embedded) {
1504
- const result = getSharedManager().getResult(jobId(id));
1505
- resolve(result);
1506
- }
1507
- else {
1508
- resolve(undefined);
1509
- }
1510
- }
1511
- else if (state === 'failed') {
1512
- cleanup();
1513
- reject(new Error('Job already failed'));
1514
- }
1515
- });
1516
- });
398
+ getWaitingChildrenCount() {
399
+ return bullmqCompatOps.getWaitingChildrenCount(this.addCtx);
400
+ }
401
+ trimEvents(maxLength) {
402
+ return workersOps.trimEvents(this.ctx, maxLength);
403
+ }
404
+ // ============ Worker/Metrics Operations ============
405
+ getWorkers() {
406
+ return workersOps.getWorkers(this.ctx);
407
+ }
408
+ getWorkersCount() {
409
+ return workersOps.getWorkersCount(this.ctx);
410
+ }
411
+ getMetrics(type, start, end) {
412
+ return workersOps.getMetrics(this.ctx, type, start, end);
413
+ }
414
+ // ============ Connection ============
415
+ disconnect() {
416
+ this.close();
417
+ return Promise.resolve();
1517
418
  }
1518
419
  close() {
1519
420
  if (this.tcpPool) {
@@ -1523,208 +424,5 @@ export class Queue {
1523
424
  this.tcpPool.close();
1524
425
  }
1525
426
  }
1526
- createJobProxy(id, name, data) {
1527
- const tcp = this.tcp;
1528
- const ts = Date.now();
1529
- return {
1530
- id,
1531
- name,
1532
- data,
1533
- queueName: this.name,
1534
- attemptsMade: 0,
1535
- timestamp: ts,
1536
- progress: 0,
1537
- // BullMQ v5 properties
1538
- delay: 0,
1539
- processedOn: undefined,
1540
- finishedOn: undefined,
1541
- stacktrace: null,
1542
- stalledCounter: 0,
1543
- priority: 0,
1544
- parentKey: undefined,
1545
- opts: {},
1546
- token: undefined,
1547
- processedBy: undefined,
1548
- deduplicationId: undefined,
1549
- repeatJobKey: undefined,
1550
- attemptsStarted: 0,
1551
- // Methods
1552
- updateProgress: async (progress, message) => {
1553
- await tcp.send({ cmd: 'Progress', id, progress, message });
1554
- },
1555
- log: async (message) => {
1556
- await tcp.send({ cmd: 'AddLog', id, message });
1557
- },
1558
- getState: () => this.getJobState(id),
1559
- remove: () => this.removeAsync(id),
1560
- retry: () => this.retryJob(id),
1561
- getChildrenValues: () => this.getChildrenValues(id),
1562
- // BullMQ v5 state check methods
1563
- isWaiting: async () => (await this.getJobState(id)) === 'waiting',
1564
- isActive: async () => (await this.getJobState(id)) === 'active',
1565
- isDelayed: async () => (await this.getJobState(id)) === 'delayed',
1566
- isCompleted: async () => (await this.getJobState(id)) === 'completed',
1567
- isFailed: async () => (await this.getJobState(id)) === 'failed',
1568
- isWaitingChildren: () => Promise.resolve(false),
1569
- // BullMQ v5 mutation methods
1570
- updateData: async (newData) => {
1571
- await tcp.send({ cmd: 'Update', id, data: newData });
1572
- },
1573
- promote: async () => {
1574
- await tcp.send({ cmd: 'Promote', id });
1575
- },
1576
- changeDelay: async (delay) => {
1577
- await tcp.send({ cmd: 'ChangeDelay', id, delay });
1578
- },
1579
- changePriority: async (opts) => {
1580
- await tcp.send({ cmd: 'ChangePriority', id, priority: opts.priority });
1581
- },
1582
- extendLock: async (_token, duration) => {
1583
- const res = await tcp.send({ cmd: 'ExtendLock', id, duration });
1584
- return res.ok ? duration : 0;
1585
- },
1586
- clearLogs: async () => {
1587
- await tcp.send({ cmd: 'ClearLogs', id });
1588
- },
1589
- // BullMQ v5 dependency methods
1590
- getDependencies: () => Promise.resolve({ processed: {}, unprocessed: [] }),
1591
- getDependenciesCount: () => Promise.resolve({ processed: 0, unprocessed: 0 }),
1592
- // BullMQ v5 serialization methods
1593
- toJSON: () => ({
1594
- id,
1595
- name,
1596
- data,
1597
- opts: {},
1598
- progress: 0,
1599
- delay: 0,
1600
- timestamp: ts,
1601
- attemptsMade: 0,
1602
- stacktrace: null,
1603
- queueQualifiedName: `bull:${this.name}`,
1604
- }),
1605
- asJSON: () => ({
1606
- id,
1607
- name,
1608
- data: JSON.stringify(data),
1609
- opts: '{}',
1610
- progress: '0',
1611
- delay: '0',
1612
- timestamp: String(ts),
1613
- attemptsMade: '0',
1614
- stacktrace: null,
1615
- }),
1616
- // BullMQ v5 move methods
1617
- moveToCompleted: async (returnValue) => {
1618
- await tcp.send({ cmd: 'ACK', id, result: returnValue });
1619
- return null;
1620
- },
1621
- moveToFailed: async (error) => {
1622
- await tcp.send({ cmd: 'FAIL', id, error: error.message });
1623
- },
1624
- moveToWait: async () => {
1625
- const res = await tcp.send({ cmd: 'MoveToWait', id });
1626
- return res.ok === true;
1627
- },
1628
- moveToDelayed: async (timestamp) => {
1629
- await tcp.send({ cmd: 'MoveToDelayed', id, timestamp });
1630
- },
1631
- moveToWaitingChildren: () => Promise.resolve(false),
1632
- waitUntilFinished: () => Promise.resolve(undefined),
1633
- // BullMQ v5 additional methods
1634
- discard: () => { },
1635
- getFailedChildrenValues: () => Promise.resolve({}),
1636
- getIgnoredChildrenFailures: () => Promise.resolve({}),
1637
- removeChildDependency: () => Promise.resolve(false),
1638
- removeDeduplicationKey: () => Promise.resolve(false),
1639
- removeUnprocessedChildren: () => Promise.resolve(),
1640
- };
1641
- }
1642
- createSimpleJob(id, name, data, timestamp) {
1643
- return {
1644
- id,
1645
- name,
1646
- data,
1647
- queueName: this.name,
1648
- attemptsMade: 0,
1649
- timestamp,
1650
- progress: 0,
1651
- // BullMQ v5 properties
1652
- delay: 0,
1653
- processedOn: undefined,
1654
- finishedOn: undefined,
1655
- stacktrace: null,
1656
- stalledCounter: 0,
1657
- priority: 0,
1658
- parentKey: undefined,
1659
- opts: {},
1660
- token: undefined,
1661
- processedBy: undefined,
1662
- deduplicationId: undefined,
1663
- repeatJobKey: undefined,
1664
- attemptsStarted: 0,
1665
- // Methods
1666
- updateProgress: async () => { },
1667
- log: async () => { },
1668
- getState: () => this.getJobState(id),
1669
- remove: () => this.removeAsync(id),
1670
- retry: () => this.retryJob(id),
1671
- getChildrenValues: () => this.getChildrenValues(id),
1672
- // BullMQ v5 state check methods
1673
- isWaiting: async () => (await this.getJobState(id)) === 'waiting',
1674
- isActive: async () => (await this.getJobState(id)) === 'active',
1675
- isDelayed: async () => (await this.getJobState(id)) === 'delayed',
1676
- isCompleted: async () => (await this.getJobState(id)) === 'completed',
1677
- isFailed: async () => (await this.getJobState(id)) === 'failed',
1678
- isWaitingChildren: () => Promise.resolve(false),
1679
- // BullMQ v5 mutation methods
1680
- updateData: async () => { },
1681
- promote: async () => { },
1682
- changeDelay: async () => { },
1683
- changePriority: async () => { },
1684
- extendLock: () => Promise.resolve(0),
1685
- clearLogs: async () => { },
1686
- // BullMQ v5 dependency methods
1687
- getDependencies: () => Promise.resolve({ processed: {}, unprocessed: [] }),
1688
- getDependenciesCount: () => Promise.resolve({ processed: 0, unprocessed: 0 }),
1689
- // BullMQ v5 serialization methods
1690
- toJSON: () => ({
1691
- id,
1692
- name,
1693
- data,
1694
- opts: {},
1695
- progress: 0,
1696
- delay: 0,
1697
- timestamp,
1698
- attemptsMade: 0,
1699
- stacktrace: null,
1700
- queueQualifiedName: `bull:${this.name}`,
1701
- }),
1702
- asJSON: () => ({
1703
- id,
1704
- name,
1705
- data: JSON.stringify(data),
1706
- opts: '{}',
1707
- progress: '0',
1708
- delay: '0',
1709
- timestamp: String(timestamp),
1710
- attemptsMade: '0',
1711
- stacktrace: null,
1712
- }),
1713
- // BullMQ v5 move methods
1714
- moveToCompleted: () => Promise.resolve(null),
1715
- moveToFailed: () => Promise.resolve(),
1716
- moveToWait: () => Promise.resolve(false),
1717
- moveToDelayed: () => Promise.resolve(),
1718
- moveToWaitingChildren: () => Promise.resolve(false),
1719
- waitUntilFinished: () => Promise.resolve(undefined),
1720
- // BullMQ v5 additional methods
1721
- discard: () => { },
1722
- getFailedChildrenValues: () => Promise.resolve({}),
1723
- getIgnoredChildrenFailures: () => Promise.resolve({}),
1724
- removeChildDependency: () => Promise.resolve(false),
1725
- removeDeduplicationKey: () => Promise.resolve(false),
1726
- removeUnprocessedChildren: () => Promise.resolve(),
1727
- };
1728
- }
1729
427
  }
1730
428
  //# sourceMappingURL=queue.js.map