bunqueue 1.9.8 → 2.0.0

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 (219) hide show
  1. package/dist/application/backgroundTasks.d.ts +10 -0
  2. package/dist/application/backgroundTasks.d.ts.map +1 -1
  3. package/dist/application/backgroundTasks.js +64 -13
  4. package/dist/application/backgroundTasks.js.map +1 -1
  5. package/dist/application/cleanupTasks.js +5 -1
  6. package/dist/application/cleanupTasks.js.map +1 -1
  7. package/dist/application/clientTracking.d.ts.map +1 -1
  8. package/dist/application/clientTracking.js +25 -16
  9. package/dist/application/clientTracking.js.map +1 -1
  10. package/dist/application/contextFactory.d.ts.map +1 -1
  11. package/dist/application/contextFactory.js +1 -0
  12. package/dist/application/contextFactory.js.map +1 -1
  13. package/dist/application/dependencyProcessor.d.ts.map +1 -1
  14. package/dist/application/dependencyProcessor.js +14 -13
  15. package/dist/application/dependencyProcessor.js.map +1 -1
  16. package/dist/application/eventsManager.d.ts.map +1 -1
  17. package/dist/application/eventsManager.js +16 -4
  18. package/dist/application/eventsManager.js.map +1 -1
  19. package/dist/application/jobLogsManager.d.ts +2 -2
  20. package/dist/application/jobLogsManager.d.ts.map +1 -1
  21. package/dist/application/jobLogsManager.js +13 -3
  22. package/dist/application/jobLogsManager.js.map +1 -1
  23. package/dist/application/lockManager.d.ts +1 -0
  24. package/dist/application/lockManager.d.ts.map +1 -1
  25. package/dist/application/lockManager.js +54 -36
  26. package/dist/application/lockManager.js.map +1 -1
  27. package/dist/application/operations/ack.d.ts +3 -1
  28. package/dist/application/operations/ack.d.ts.map +1 -1
  29. package/dist/application/operations/ack.js +25 -1
  30. package/dist/application/operations/ack.js.map +1 -1
  31. package/dist/application/operations/ackHelpers.d.ts +1 -0
  32. package/dist/application/operations/ackHelpers.d.ts.map +1 -1
  33. package/dist/application/operations/ackHelpers.js +12 -1
  34. package/dist/application/operations/ackHelpers.js.map +1 -1
  35. package/dist/application/operations/jobManagement.d.ts +1 -1
  36. package/dist/application/operations/jobManagement.d.ts.map +1 -1
  37. package/dist/application/operations/jobManagement.js +23 -3
  38. package/dist/application/operations/jobManagement.js.map +1 -1
  39. package/dist/application/operations/push.d.ts +1 -1
  40. package/dist/application/operations/push.d.ts.map +1 -1
  41. package/dist/application/operations/push.js +25 -9
  42. package/dist/application/operations/push.js.map +1 -1
  43. package/dist/application/operations/queryOperations.d.ts +3 -0
  44. package/dist/application/operations/queryOperations.d.ts.map +1 -1
  45. package/dist/application/operations/queryOperations.js +29 -0
  46. package/dist/application/operations/queryOperations.js.map +1 -1
  47. package/dist/application/queueManager.d.ts +15 -1
  48. package/dist/application/queueManager.d.ts.map +1 -1
  49. package/dist/application/queueManager.js +77 -3
  50. package/dist/application/queueManager.js.map +1 -1
  51. package/dist/application/stallDetection.js +27 -22
  52. package/dist/application/stallDetection.js.map +1 -1
  53. package/dist/application/types.js +1 -1
  54. package/dist/application/types.js.map +1 -1
  55. package/dist/application/webhookManager.d.ts.map +1 -1
  56. package/dist/application/webhookManager.js +18 -2
  57. package/dist/application/webhookManager.js.map +1 -1
  58. package/dist/application/workerManager.d.ts.map +1 -1
  59. package/dist/application/workerManager.js +4 -2
  60. package/dist/application/workerManager.js.map +1 -1
  61. package/dist/cli/client.d.ts +3 -5
  62. package/dist/cli/client.d.ts.map +1 -1
  63. package/dist/cli/client.js +31 -27
  64. package/dist/cli/client.js.map +1 -1
  65. package/dist/cli/commands/core.js +3 -3
  66. package/dist/cli/commands/core.js.map +1 -1
  67. package/dist/cli/commands/job.js +14 -14
  68. package/dist/cli/commands/job.js.map +1 -1
  69. package/dist/cli/commands/server.d.ts.map +1 -1
  70. package/dist/cli/commands/server.js +5 -29
  71. package/dist/cli/commands/server.js.map +1 -1
  72. package/dist/cli/index.d.ts.map +1 -1
  73. package/dist/cli/index.js +1 -9
  74. package/dist/cli/index.js.map +1 -1
  75. package/dist/client/events.d.ts +29 -1
  76. package/dist/client/events.d.ts.map +1 -1
  77. package/dist/client/events.js +96 -28
  78. package/dist/client/events.js.map +1 -1
  79. package/dist/client/flow.d.ts +144 -3
  80. package/dist/client/flow.d.ts.map +1 -1
  81. package/dist/client/flow.js +538 -68
  82. package/dist/client/flow.js.map +1 -1
  83. package/dist/client/index.d.ts +2 -2
  84. package/dist/client/index.d.ts.map +1 -1
  85. package/dist/client/queue/queue.d.ts +260 -1
  86. package/dist/client/queue/queue.d.ts.map +1 -1
  87. package/dist/client/queue/queue.js +1346 -17
  88. package/dist/client/queue/queue.js.map +1 -1
  89. package/dist/client/sandboxed/types.d.ts +1 -0
  90. package/dist/client/sandboxed/types.d.ts.map +1 -1
  91. package/dist/client/sandboxed/worker.d.ts +1 -0
  92. package/dist/client/sandboxed/worker.d.ts.map +1 -1
  93. package/dist/client/sandboxed/worker.js +31 -8
  94. package/dist/client/sandboxed/worker.js.map +1 -1
  95. package/dist/client/sandboxed/wrapper.d.ts.map +1 -1
  96. package/dist/client/sandboxed/wrapper.js +10 -1
  97. package/dist/client/sandboxed/wrapper.js.map +1 -1
  98. package/dist/client/tcp/client.d.ts +4 -1
  99. package/dist/client/tcp/client.d.ts.map +1 -1
  100. package/dist/client/tcp/client.js +26 -8
  101. package/dist/client/tcp/client.js.map +1 -1
  102. package/dist/client/tcp/connection.d.ts +6 -8
  103. package/dist/client/tcp/connection.d.ts.map +1 -1
  104. package/dist/client/tcp/connection.js +24 -22
  105. package/dist/client/tcp/connection.js.map +1 -1
  106. package/dist/client/tcp/index.d.ts +0 -1
  107. package/dist/client/tcp/index.d.ts.map +1 -1
  108. package/dist/client/tcp/index.js +0 -1
  109. package/dist/client/tcp/index.js.map +1 -1
  110. package/dist/client/tcp/types.d.ts +8 -13
  111. package/dist/client/tcp/types.d.ts.map +1 -1
  112. package/dist/client/tcp/types.js +0 -1
  113. package/dist/client/tcp/types.js.map +1 -1
  114. package/dist/client/tcpPool.d.ts.map +1 -1
  115. package/dist/client/tcpPool.js +19 -14
  116. package/dist/client/tcpPool.js.map +1 -1
  117. package/dist/client/types.d.ts +430 -13
  118. package/dist/client/types.d.ts.map +1 -1
  119. package/dist/client/types.js +346 -5
  120. package/dist/client/types.js.map +1 -1
  121. package/dist/client/worker/ackBatcher.d.ts +2 -1
  122. package/dist/client/worker/ackBatcher.d.ts.map +1 -1
  123. package/dist/client/worker/ackBatcher.js +29 -18
  124. package/dist/client/worker/ackBatcher.js.map +1 -1
  125. package/dist/client/worker/jobParser.d.ts.map +1 -1
  126. package/dist/client/worker/jobParser.js +8 -7
  127. package/dist/client/worker/jobParser.js.map +1 -1
  128. package/dist/client/worker/processor.d.ts.map +1 -1
  129. package/dist/client/worker/processor.js +15 -6
  130. package/dist/client/worker/processor.js.map +1 -1
  131. package/dist/client/worker/worker.d.ts +117 -0
  132. package/dist/client/worker/worker.d.ts.map +1 -1
  133. package/dist/client/worker/worker.js +375 -3
  134. package/dist/client/worker/worker.js.map +1 -1
  135. package/dist/domain/queue/dlqShard.d.ts +2 -0
  136. package/dist/domain/queue/dlqShard.d.ts.map +1 -1
  137. package/dist/domain/queue/dlqShard.js +12 -2
  138. package/dist/domain/queue/dlqShard.js.map +1 -1
  139. package/dist/domain/queue/priorityQueue.d.ts.map +1 -1
  140. package/dist/domain/queue/priorityQueue.js +24 -18
  141. package/dist/domain/queue/priorityQueue.js.map +1 -1
  142. package/dist/domain/queue/shard.d.ts +8 -2
  143. package/dist/domain/queue/shard.d.ts.map +1 -1
  144. package/dist/domain/queue/shard.js +27 -9
  145. package/dist/domain/queue/shard.js.map +1 -1
  146. package/dist/domain/queue/temporalManager.d.ts +1 -0
  147. package/dist/domain/queue/temporalManager.d.ts.map +1 -1
  148. package/dist/domain/queue/temporalManager.js +2 -1
  149. package/dist/domain/queue/temporalManager.js.map +1 -1
  150. package/dist/domain/queue/uniqueKeyManager.d.ts +2 -2
  151. package/dist/domain/queue/uniqueKeyManager.d.ts.map +1 -1
  152. package/dist/domain/queue/uniqueKeyManager.js +3 -3
  153. package/dist/domain/queue/uniqueKeyManager.js.map +1 -1
  154. package/dist/domain/types/command.d.ts +6 -0
  155. package/dist/domain/types/command.d.ts.map +1 -1
  156. package/dist/domain/types/job.d.ts +89 -2
  157. package/dist/domain/types/job.d.ts.map +1 -1
  158. package/dist/domain/types/job.js +94 -26
  159. package/dist/domain/types/job.js.map +1 -1
  160. package/dist/domain/types/queue.d.ts +11 -1
  161. package/dist/domain/types/queue.d.ts.map +1 -1
  162. package/dist/infrastructure/persistence/sqlite.d.ts +2 -0
  163. package/dist/infrastructure/persistence/sqlite.d.ts.map +1 -1
  164. package/dist/infrastructure/persistence/sqlite.js +5 -1
  165. package/dist/infrastructure/persistence/sqlite.js.map +1 -1
  166. package/dist/infrastructure/persistence/sqliteBatch.d.ts +9 -4
  167. package/dist/infrastructure/persistence/sqliteBatch.d.ts.map +1 -1
  168. package/dist/infrastructure/persistence/sqliteBatch.js +38 -21
  169. package/dist/infrastructure/persistence/sqliteBatch.js.map +1 -1
  170. package/dist/infrastructure/persistence/sqliteSerializer.d.ts.map +1 -1
  171. package/dist/infrastructure/persistence/sqliteSerializer.js +14 -0
  172. package/dist/infrastructure/persistence/sqliteSerializer.js.map +1 -1
  173. package/dist/infrastructure/persistence/statements.d.ts +1 -1
  174. package/dist/infrastructure/persistence/statements.d.ts.map +1 -1
  175. package/dist/infrastructure/persistence/statements.js +3 -2
  176. package/dist/infrastructure/persistence/statements.js.map +1 -1
  177. package/dist/infrastructure/scheduler/cronScheduler.d.ts +7 -0
  178. package/dist/infrastructure/scheduler/cronScheduler.d.ts.map +1 -1
  179. package/dist/infrastructure/scheduler/cronScheduler.js +46 -12
  180. package/dist/infrastructure/scheduler/cronScheduler.js.map +1 -1
  181. package/dist/infrastructure/server/handlers/core.d.ts.map +1 -1
  182. package/dist/infrastructure/server/handlers/core.js +26 -19
  183. package/dist/infrastructure/server/handlers/core.js.map +1 -1
  184. package/dist/infrastructure/server/handlers/query.d.ts.map +1 -1
  185. package/dist/infrastructure/server/handlers/query.js +1 -16
  186. package/dist/infrastructure/server/handlers/query.js.map +1 -1
  187. package/dist/infrastructure/server/http.d.ts.map +1 -1
  188. package/dist/infrastructure/server/http.js +27 -2
  189. package/dist/infrastructure/server/http.js.map +1 -1
  190. package/dist/infrastructure/server/protocol.d.ts +15 -1
  191. package/dist/infrastructure/server/protocol.d.ts.map +1 -1
  192. package/dist/infrastructure/server/protocol.js +37 -3
  193. package/dist/infrastructure/server/protocol.js.map +1 -1
  194. package/dist/infrastructure/server/rateLimiter.d.ts.map +1 -1
  195. package/dist/infrastructure/server/rateLimiter.js +5 -3
  196. package/dist/infrastructure/server/rateLimiter.js.map +1 -1
  197. package/dist/infrastructure/server/tcp.d.ts +8 -10
  198. package/dist/infrastructure/server/tcp.d.ts.map +1 -1
  199. package/dist/infrastructure/server/tcp.js +87 -46
  200. package/dist/infrastructure/server/tcp.js.map +1 -1
  201. package/dist/main.js +7 -6
  202. package/dist/main.js.map +1 -1
  203. package/dist/shared/lock.d.ts +1 -1
  204. package/dist/shared/lock.d.ts.map +1 -1
  205. package/dist/shared/lock.js +6 -4
  206. package/dist/shared/lock.js.map +1 -1
  207. package/dist/shared/lru.d.ts +51 -0
  208. package/dist/shared/lru.d.ts.map +1 -1
  209. package/dist/shared/lru.js +89 -3
  210. package/dist/shared/lru.js.map +1 -1
  211. package/dist/shared/skipList.d.ts +10 -2
  212. package/dist/shared/skipList.d.ts.map +1 -1
  213. package/dist/shared/skipList.js +22 -1
  214. package/dist/shared/skipList.js.map +1 -1
  215. package/package.json +1 -1
  216. package/dist/client/tcp/lineBuffer.d.ts +0 -17
  217. package/dist/client/tcp/lineBuffer.d.ts.map +0 -1
  218. package/dist/client/tcp/lineBuffer.js +0 -32
  219. package/dist/client/tcp/lineBuffer.js.map +0 -1
@@ -51,38 +51,105 @@ export class Queue {
51
51
  /** Add a job to the queue */
52
52
  async add(name, data, opts = {}) {
53
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
+ }
54
60
  if (this.embedded) {
55
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;
56
89
  const job = await manager.push(this.name, {
57
- data: { name, ...data },
90
+ data: jobData,
58
91
  priority: merged.priority,
59
92
  delay: merged.delay,
60
93
  maxAttempts: merged.attempts,
61
94
  backoff: merged.backoff,
62
95
  timeout: merged.timeout,
63
- customId: merged.jobId,
64
- removeOnComplete: merged.removeOnComplete,
65
- removeOnFail: merged.removeOnFail,
66
- repeat: merged.repeat,
96
+ customId: merged.jobId ?? merged.deduplication?.id,
97
+ removeOnComplete,
98
+ removeOnFail,
99
+ repeat,
67
100
  stallTimeout: merged.stallTimeout,
68
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),
69
135
  });
70
- return toPublicJob(job, name);
71
136
  }
72
137
  const response = await this.tcp.send({
73
138
  cmd: 'PUSH',
74
139
  queue: this.name,
75
- data: { name, ...data },
140
+ data: jobData,
76
141
  priority: merged.priority,
77
142
  delay: merged.delay,
78
143
  maxAttempts: merged.attempts,
79
144
  backoff: merged.backoff,
80
145
  timeout: merged.timeout,
81
- customId: merged.jobId,
146
+ jobId: merged.jobId,
82
147
  removeOnComplete: merged.removeOnComplete,
83
148
  removeOnFail: merged.removeOnFail,
84
149
  stallTimeout: merged.stallTimeout,
85
150
  durable: merged.durable,
151
+ repeat: merged.repeat,
152
+ parentId: merged.parent?.id,
86
153
  });
87
154
  if (!response.ok) {
88
155
  throw new Error(response.error ?? 'Failed to add job');
@@ -99,6 +166,9 @@ export class Queue {
99
166
  const manager = getSharedManager();
100
167
  const inputs = jobs.map(({ name, data, opts }) => {
101
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;
102
172
  return {
103
173
  data: { name, ...data },
104
174
  priority: m.priority,
@@ -107,10 +177,43 @@ export class Queue {
107
177
  backoff: m.backoff,
108
178
  timeout: m.timeout,
109
179
  customId: m.jobId,
110
- removeOnComplete: m.removeOnComplete,
111
- removeOnFail: m.removeOnFail,
112
- repeat: m.repeat,
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,
113
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,
114
217
  };
115
218
  });
116
219
  const ids = await manager.pushBatch(this.name, inputs);
@@ -129,6 +232,8 @@ export class Queue {
129
232
  removeOnComplete: m.removeOnComplete,
130
233
  removeOnFail: m.removeOnFail,
131
234
  stallTimeout: m.stallTimeout,
235
+ repeat: m.repeat,
236
+ durable: m.durable,
132
237
  };
133
238
  });
134
239
  const response = await this.tcp.send({ cmd: 'PUSHB', queue: this.name, jobs: jobInputs });
@@ -146,23 +251,121 @@ export class Queue {
146
251
  if (!job)
147
252
  return null;
148
253
  const jobData = job.data;
149
- return toPublicJob(job, jobData?.name ?? 'default');
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
+ });
150
276
  }
151
277
  const response = await this.tcp.send({ cmd: 'GetJob', id });
152
278
  if (!response.ok || !response.job)
153
279
  return null;
154
280
  const jobData = response.job;
155
281
  const data = jobData.data;
282
+ const jobIdStr = String(jobData.id);
283
+ const ts = jobData.createdAt ?? Date.now();
284
+ const runAt = jobData.runAt ?? ts;
156
285
  return {
157
- id: String(jobData.id),
286
+ id: jobIdStr,
158
287
  name: data?.name ?? 'default',
159
288
  data: jobData.data,
160
289
  queueName: this.name,
161
290
  attemptsMade: jobData.attempts ?? 0,
162
- timestamp: jobData.createdAt ?? Date.now(),
291
+ timestamp: ts,
163
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
164
308
  updateProgress: async () => { },
165
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(),
166
369
  };
167
370
  }
168
371
  /** Remove a job by ID */
@@ -172,6 +375,55 @@ export class Queue {
172
375
  else
173
376
  void this.tcp.send({ cmd: 'Cancel', id });
174
377
  }
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
+ }
386
+ }
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
+ }
401
+ }
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
+ 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({});
414
+ }
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;
426
+ }
175
427
  /** Get job counts by state */
176
428
  getJobCounts() {
177
429
  if (this.embedded) {
@@ -236,13 +488,309 @@ export class Queue {
236
488
  else
237
489
  void this.tcp.send({ cmd: 'Obliterate', queue: this.name });
238
490
  }
491
+ /** Check if queue is paused */
492
+ 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;
588
+ }
589
+ /** Get waiting job count */
590
+ async getWaitingCount() {
591
+ const counts = await this.getJobCountsAsync();
592
+ return counts.waiting;
593
+ }
594
+ /** Clean old jobs from the queue */
595
+ 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;
654
+ }
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;
677
+ }
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 });
687
+ }
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
+ }
696
+ }
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
+ }
705
+ }
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);
711
+ }
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
+ }
720
+ }
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
+ }
729
+ }
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);
735
+ }
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
+ }
239
766
  /** Get jobs with filtering and pagination */
240
767
  getJobs(options = {}) {
241
768
  if (this.embedded) {
242
769
  const jobs = getSharedManager().getJobs(this.name, options);
243
770
  return jobs.map((job) => {
244
771
  const jobData = job.data;
245
- return toPublicJob(job, jobData?.name ?? 'default');
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
+ });
246
794
  });
247
795
  }
248
796
  // Sync TCP version returns empty - use getJobsAsync
@@ -265,16 +813,91 @@ export class Queue {
265
813
  const jobs = response.jobs;
266
814
  return jobs.map((j) => {
267
815
  const jobData = j.data;
816
+ const jobName = jobData?.name ?? 'default';
268
817
  return {
269
818
  id: j.id,
270
- name: jobData?.name ?? 'default',
819
+ name: jobName,
271
820
  data: j.data,
272
821
  queueName: j.queue,
273
822
  attemptsMade: j.attempts,
274
823
  timestamp: j.createdAt,
275
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
276
840
  updateProgress: async () => { },
277
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(),
278
901
  };
279
902
  });
280
903
  }
@@ -358,6 +981,540 @@ export class Queue {
358
981
  return 0;
359
982
  return response.count ?? 0;
360
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();
1006
+ }
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
+ });
1064
+ }
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
+ }
1089
+ }
1090
+ /**
1091
+ * Check if the queue is currently rate limited (at max capacity).
1092
+ */
1093
+ 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
+ }
1141
+ }
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
+ }
1154
+ }
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
+ }
1188
+ }
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
+ }
1220
+ }
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
+ */
1232
+ 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);
1239
+ }
1240
+ /**
1241
+ * Remove a deduplication key, allowing a new job with the same key.
1242
+ */
1243
+ 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' });
1269
+ }
1270
+ /**
1271
+ * Disconnect from the server (async version of close).
1272
+ */
1273
+ disconnect() {
1274
+ this.close();
1275
+ return Promise.resolve();
1276
+ }
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
+ }
1289
+ }
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
+ }
1298
+ }
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
+ }
1308
+ }
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
+ }
1318
+ }
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
+ }
1330
+ }
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
+ }
1340
+ }
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: [] };
1366
+ }
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
+ }
1395
+ }
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
+ }
1408
+ }
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
+ }
1431
+ }
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
+ }
1445
+ }
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
+ });
1517
+ }
361
1518
  close() {
362
1519
  if (this.tcpPool) {
363
1520
  if (this.useSharedPool)
@@ -368,20 +1525,118 @@ export class Queue {
368
1525
  }
369
1526
  createJobProxy(id, name, data) {
370
1527
  const tcp = this.tcp;
1528
+ const ts = Date.now();
371
1529
  return {
372
1530
  id,
373
1531
  name,
374
1532
  data,
375
1533
  queueName: this.name,
376
1534
  attemptsMade: 0,
377
- timestamp: Date.now(),
1535
+ timestamp: ts,
378
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
379
1552
  updateProgress: async (progress, message) => {
380
1553
  await tcp.send({ cmd: 'Progress', id, progress, message });
381
1554
  },
382
1555
  log: async (message) => {
383
1556
  await tcp.send({ cmd: 'AddLog', id, message });
384
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(),
385
1640
  };
386
1641
  }
387
1642
  createSimpleJob(id, name, data, timestamp) {
@@ -393,8 +1648,82 @@ export class Queue {
393
1648
  attemptsMade: 0,
394
1649
  timestamp,
395
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
396
1666
  updateProgress: async () => { },
397
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(),
398
1727
  };
399
1728
  }
400
1729
  }