bunqueue 2.0.1 → 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.
- package/dist/application/backgroundTasks.d.ts.map +1 -1
- package/dist/application/backgroundTasks.js +108 -11
- package/dist/application/backgroundTasks.js.map +1 -1
- package/dist/application/operations/jobManagement.d.ts.map +1 -1
- package/dist/application/operations/jobManagement.js +1 -0
- package/dist/application/operations/jobManagement.js.map +1 -1
- package/dist/application/queueManager.d.ts +8 -0
- package/dist/application/queueManager.d.ts.map +1 -1
- package/dist/application/queueManager.js +40 -0
- package/dist/application/queueManager.js.map +1 -1
- package/dist/client/queue/bullmqCompat.d.ts +46 -0
- package/dist/client/queue/bullmqCompat.d.ts.map +1 -0
- package/dist/client/queue/bullmqCompat.js +97 -0
- package/dist/client/queue/bullmqCompat.js.map +1 -0
- package/dist/client/queue/deduplication.d.ts +13 -0
- package/dist/client/queue/deduplication.d.ts.map +1 -0
- package/dist/client/queue/deduplication.js +24 -0
- package/dist/client/queue/deduplication.js.map +1 -0
- package/dist/client/queue/dlq.d.ts +31 -0
- package/dist/client/queue/dlq.d.ts.map +1 -0
- package/dist/client/queue/dlq.js +85 -0
- package/dist/client/queue/dlq.js.map +1 -0
- package/dist/client/queue/jobMove.d.ts +33 -0
- package/dist/client/queue/jobMove.d.ts.map +1 -0
- package/dist/client/queue/jobMove.js +113 -0
- package/dist/client/queue/jobMove.js.map +1 -0
- package/dist/client/queue/jobProxy.d.ts +28 -0
- package/dist/client/queue/jobProxy.d.ts.map +1 -0
- package/dist/client/queue/jobProxy.js +209 -0
- package/dist/client/queue/jobProxy.js.map +1 -0
- package/dist/client/queue/operations/add.d.ts +47 -0
- package/dist/client/queue/operations/add.d.ts.map +1 -0
- package/dist/client/queue/operations/add.js +226 -0
- package/dist/client/queue/operations/add.js.map +1 -0
- package/dist/client/queue/operations/control.d.ts +26 -0
- package/dist/client/queue/operations/control.d.ts.map +1 -0
- package/dist/client/queue/operations/control.js +56 -0
- package/dist/client/queue/operations/control.js.map +1 -0
- package/dist/client/queue/operations/counts.d.ts +40 -0
- package/dist/client/queue/operations/counts.d.ts.map +1 -0
- package/dist/client/queue/operations/counts.js +99 -0
- package/dist/client/queue/operations/counts.js.map +1 -0
- package/dist/client/queue/operations/index.d.ts +10 -0
- package/dist/client/queue/operations/index.d.ts.map +1 -0
- package/dist/client/queue/operations/index.js +10 -0
- package/dist/client/queue/operations/index.js.map +1 -0
- package/dist/client/queue/operations/management.d.ts +56 -0
- package/dist/client/queue/operations/management.d.ts.map +1 -0
- package/dist/client/queue/operations/management.js +181 -0
- package/dist/client/queue/operations/management.js.map +1 -0
- package/dist/client/queue/operations/query.d.ts +58 -0
- package/dist/client/queue/operations/query.d.ts.map +1 -0
- package/dist/client/queue/operations/query.js +191 -0
- package/dist/client/queue/operations/query.js.map +1 -0
- package/dist/client/queue/queue.d.ts +93 -272
- package/dist/client/queue/queue.d.ts.map +1 -1
- package/dist/client/queue/queue.js +297 -1599
- package/dist/client/queue/queue.js.map +1 -1
- package/dist/client/queue/queueTypes.d.ts +34 -0
- package/dist/client/queue/queueTypes.d.ts.map +1 -0
- package/dist/client/queue/queueTypes.js +6 -0
- package/dist/client/queue/queueTypes.js.map +1 -0
- package/dist/client/queue/rateLimit.d.ts +32 -0
- package/dist/client/queue/rateLimit.d.ts.map +1 -0
- package/dist/client/queue/rateLimit.js +69 -0
- package/dist/client/queue/rateLimit.js.map +1 -0
- package/dist/client/queue/scheduler.d.ts +44 -0
- package/dist/client/queue/scheduler.d.ts.map +1 -0
- package/dist/client/queue/scheduler.js +114 -0
- package/dist/client/queue/scheduler.js.map +1 -0
- package/dist/client/queue/stall.d.ts +15 -0
- package/dist/client/queue/stall.d.ts.map +1 -0
- package/dist/client/queue/stall.js +21 -0
- package/dist/client/queue/stall.js.map +1 -0
- package/dist/client/queue/workers.d.ts +29 -0
- package/dist/client/queue/workers.d.ts.map +1 -0
- package/dist/client/queue/workers.js +39 -0
- package/dist/client/queue/workers.js.map +1 -0
- package/dist/client/sandboxed/worker.d.ts.map +1 -1
- package/dist/client/sandboxed/worker.js +12 -1
- package/dist/client/sandboxed/worker.js.map +1 -1
- package/dist/infrastructure/persistence/sqlite.d.ts +25 -2
- package/dist/infrastructure/persistence/sqlite.d.ts.map +1 -1
- package/dist/infrastructure/persistence/sqlite.js +47 -6
- package/dist/infrastructure/persistence/sqlite.js.map +1 -1
- package/dist/infrastructure/server/handlers/query.d.ts +1 -1
- package/dist/infrastructure/server/handlers/query.d.ts.map +1 -1
- package/dist/infrastructure/server/handlers/query.js +4 -11
- package/dist/infrastructure/server/handlers/query.js.map +1 -1
- 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
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
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
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
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
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
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
|
-
|
|
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
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
return
|
|
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
|
-
|
|
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
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
return
|
|
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
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
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
|
-
|
|
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
|
-
|
|
656
|
-
|
|
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
|
-
|
|
679
|
-
|
|
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
|
-
|
|
689
|
-
|
|
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
|
-
|
|
698
|
-
|
|
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
|
-
|
|
707
|
-
|
|
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
|
-
|
|
713
|
-
|
|
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
|
-
|
|
722
|
-
|
|
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
|
-
|
|
731
|
-
|
|
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
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
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
|
-
|
|
264
|
+
extendJobLock(id, token, duration) {
|
|
265
|
+
return managementOps.extendJobLock(this.ctx, id, token, duration);
|
|
266
|
+
}
|
|
267
|
+
// ============ Stall Detection ============
|
|
905
268
|
setStallConfig(config) {
|
|
906
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
928
|
-
return {};
|
|
929
|
-
return dlqOps.getDlqConfigEmbedded(this.name);
|
|
279
|
+
return dlqOps.getDlqConfig(this.ctx);
|
|
930
280
|
}
|
|
931
281
|
getDlq(filter) {
|
|
932
|
-
|
|
933
|
-
return [];
|
|
934
|
-
return dlqOps.getDlqEntries(this.name, filter);
|
|
282
|
+
return dlqOps.getDlq(this.ctx, filter);
|
|
935
283
|
}
|
|
936
284
|
getDlqStats() {
|
|
937
|
-
|
|
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
|
-
|
|
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
|
-
|
|
957
|
-
return 0;
|
|
958
|
-
return dlqOps.retryDlqByFilterEmbedded(this.name, filter);
|
|
291
|
+
return dlqOps.retryDlqByFilter(this.ctx, filter);
|
|
959
292
|
}
|
|
960
293
|
purgeDlq() {
|
|
961
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
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
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1291
|
-
|
|
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
|
-
|
|
1300
|
-
|
|
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
|
-
|
|
1310
|
-
|
|
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
|
-
|
|
1320
|
-
|
|
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
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
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
|
-
|
|
1342
|
-
|
|
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
|
-
|
|
1368
|
-
|
|
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
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
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
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
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
|