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.
- package/dist/application/backgroundTasks.d.ts +10 -0
- package/dist/application/backgroundTasks.d.ts.map +1 -1
- package/dist/application/backgroundTasks.js +64 -13
- package/dist/application/backgroundTasks.js.map +1 -1
- package/dist/application/cleanupTasks.js +5 -1
- package/dist/application/cleanupTasks.js.map +1 -1
- package/dist/application/clientTracking.d.ts.map +1 -1
- package/dist/application/clientTracking.js +25 -16
- package/dist/application/clientTracking.js.map +1 -1
- package/dist/application/contextFactory.d.ts.map +1 -1
- package/dist/application/contextFactory.js +1 -0
- package/dist/application/contextFactory.js.map +1 -1
- package/dist/application/dependencyProcessor.d.ts.map +1 -1
- package/dist/application/dependencyProcessor.js +14 -13
- package/dist/application/dependencyProcessor.js.map +1 -1
- package/dist/application/eventsManager.d.ts.map +1 -1
- package/dist/application/eventsManager.js +16 -4
- package/dist/application/eventsManager.js.map +1 -1
- package/dist/application/jobLogsManager.d.ts +2 -2
- package/dist/application/jobLogsManager.d.ts.map +1 -1
- package/dist/application/jobLogsManager.js +13 -3
- package/dist/application/jobLogsManager.js.map +1 -1
- package/dist/application/lockManager.d.ts +1 -0
- package/dist/application/lockManager.d.ts.map +1 -1
- package/dist/application/lockManager.js +54 -36
- package/dist/application/lockManager.js.map +1 -1
- package/dist/application/operations/ack.d.ts +3 -1
- package/dist/application/operations/ack.d.ts.map +1 -1
- package/dist/application/operations/ack.js +25 -1
- package/dist/application/operations/ack.js.map +1 -1
- package/dist/application/operations/ackHelpers.d.ts +1 -0
- package/dist/application/operations/ackHelpers.d.ts.map +1 -1
- package/dist/application/operations/ackHelpers.js +12 -1
- package/dist/application/operations/ackHelpers.js.map +1 -1
- package/dist/application/operations/jobManagement.d.ts +1 -1
- package/dist/application/operations/jobManagement.d.ts.map +1 -1
- package/dist/application/operations/jobManagement.js +23 -3
- package/dist/application/operations/jobManagement.js.map +1 -1
- package/dist/application/operations/push.d.ts +1 -1
- package/dist/application/operations/push.d.ts.map +1 -1
- package/dist/application/operations/push.js +25 -9
- package/dist/application/operations/push.js.map +1 -1
- package/dist/application/operations/queryOperations.d.ts +3 -0
- package/dist/application/operations/queryOperations.d.ts.map +1 -1
- package/dist/application/operations/queryOperations.js +29 -0
- package/dist/application/operations/queryOperations.js.map +1 -1
- package/dist/application/queueManager.d.ts +15 -1
- package/dist/application/queueManager.d.ts.map +1 -1
- package/dist/application/queueManager.js +77 -3
- package/dist/application/queueManager.js.map +1 -1
- package/dist/application/stallDetection.js +27 -22
- package/dist/application/stallDetection.js.map +1 -1
- package/dist/application/types.js +1 -1
- package/dist/application/types.js.map +1 -1
- package/dist/application/webhookManager.d.ts.map +1 -1
- package/dist/application/webhookManager.js +18 -2
- package/dist/application/webhookManager.js.map +1 -1
- package/dist/application/workerManager.d.ts.map +1 -1
- package/dist/application/workerManager.js +4 -2
- package/dist/application/workerManager.js.map +1 -1
- package/dist/cli/client.d.ts +3 -5
- package/dist/cli/client.d.ts.map +1 -1
- package/dist/cli/client.js +31 -27
- package/dist/cli/client.js.map +1 -1
- package/dist/cli/commands/core.js +3 -3
- package/dist/cli/commands/core.js.map +1 -1
- package/dist/cli/commands/job.js +14 -14
- package/dist/cli/commands/job.js.map +1 -1
- package/dist/cli/commands/server.d.ts.map +1 -1
- package/dist/cli/commands/server.js +5 -29
- package/dist/cli/commands/server.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/client/events.d.ts +29 -1
- package/dist/client/events.d.ts.map +1 -1
- package/dist/client/events.js +96 -28
- package/dist/client/events.js.map +1 -1
- package/dist/client/flow.d.ts +144 -3
- package/dist/client/flow.d.ts.map +1 -1
- package/dist/client/flow.js +538 -68
- package/dist/client/flow.js.map +1 -1
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/queue/queue.d.ts +260 -1
- package/dist/client/queue/queue.d.ts.map +1 -1
- package/dist/client/queue/queue.js +1346 -17
- package/dist/client/queue/queue.js.map +1 -1
- package/dist/client/sandboxed/types.d.ts +1 -0
- package/dist/client/sandboxed/types.d.ts.map +1 -1
- package/dist/client/sandboxed/worker.d.ts +1 -0
- package/dist/client/sandboxed/worker.d.ts.map +1 -1
- package/dist/client/sandboxed/worker.js +31 -8
- package/dist/client/sandboxed/worker.js.map +1 -1
- package/dist/client/sandboxed/wrapper.d.ts.map +1 -1
- package/dist/client/sandboxed/wrapper.js +10 -1
- package/dist/client/sandboxed/wrapper.js.map +1 -1
- package/dist/client/tcp/client.d.ts +4 -1
- package/dist/client/tcp/client.d.ts.map +1 -1
- package/dist/client/tcp/client.js +26 -8
- package/dist/client/tcp/client.js.map +1 -1
- package/dist/client/tcp/connection.d.ts +6 -8
- package/dist/client/tcp/connection.d.ts.map +1 -1
- package/dist/client/tcp/connection.js +24 -22
- package/dist/client/tcp/connection.js.map +1 -1
- package/dist/client/tcp/index.d.ts +0 -1
- package/dist/client/tcp/index.d.ts.map +1 -1
- package/dist/client/tcp/index.js +0 -1
- package/dist/client/tcp/index.js.map +1 -1
- package/dist/client/tcp/types.d.ts +8 -13
- package/dist/client/tcp/types.d.ts.map +1 -1
- package/dist/client/tcp/types.js +0 -1
- package/dist/client/tcp/types.js.map +1 -1
- package/dist/client/tcpPool.d.ts.map +1 -1
- package/dist/client/tcpPool.js +19 -14
- package/dist/client/tcpPool.js.map +1 -1
- package/dist/client/types.d.ts +430 -13
- package/dist/client/types.d.ts.map +1 -1
- package/dist/client/types.js +346 -5
- package/dist/client/types.js.map +1 -1
- package/dist/client/worker/ackBatcher.d.ts +2 -1
- package/dist/client/worker/ackBatcher.d.ts.map +1 -1
- package/dist/client/worker/ackBatcher.js +29 -18
- package/dist/client/worker/ackBatcher.js.map +1 -1
- package/dist/client/worker/jobParser.d.ts.map +1 -1
- package/dist/client/worker/jobParser.js +8 -7
- package/dist/client/worker/jobParser.js.map +1 -1
- package/dist/client/worker/processor.d.ts.map +1 -1
- package/dist/client/worker/processor.js +15 -6
- package/dist/client/worker/processor.js.map +1 -1
- package/dist/client/worker/worker.d.ts +117 -0
- package/dist/client/worker/worker.d.ts.map +1 -1
- package/dist/client/worker/worker.js +375 -3
- package/dist/client/worker/worker.js.map +1 -1
- package/dist/domain/queue/dlqShard.d.ts +2 -0
- package/dist/domain/queue/dlqShard.d.ts.map +1 -1
- package/dist/domain/queue/dlqShard.js +12 -2
- package/dist/domain/queue/dlqShard.js.map +1 -1
- package/dist/domain/queue/priorityQueue.d.ts.map +1 -1
- package/dist/domain/queue/priorityQueue.js +24 -18
- package/dist/domain/queue/priorityQueue.js.map +1 -1
- package/dist/domain/queue/shard.d.ts +8 -2
- package/dist/domain/queue/shard.d.ts.map +1 -1
- package/dist/domain/queue/shard.js +27 -9
- package/dist/domain/queue/shard.js.map +1 -1
- package/dist/domain/queue/temporalManager.d.ts +1 -0
- package/dist/domain/queue/temporalManager.d.ts.map +1 -1
- package/dist/domain/queue/temporalManager.js +2 -1
- package/dist/domain/queue/temporalManager.js.map +1 -1
- package/dist/domain/queue/uniqueKeyManager.d.ts +2 -2
- package/dist/domain/queue/uniqueKeyManager.d.ts.map +1 -1
- package/dist/domain/queue/uniqueKeyManager.js +3 -3
- package/dist/domain/queue/uniqueKeyManager.js.map +1 -1
- package/dist/domain/types/command.d.ts +6 -0
- package/dist/domain/types/command.d.ts.map +1 -1
- package/dist/domain/types/job.d.ts +89 -2
- package/dist/domain/types/job.d.ts.map +1 -1
- package/dist/domain/types/job.js +94 -26
- package/dist/domain/types/job.js.map +1 -1
- package/dist/domain/types/queue.d.ts +11 -1
- package/dist/domain/types/queue.d.ts.map +1 -1
- package/dist/infrastructure/persistence/sqlite.d.ts +2 -0
- package/dist/infrastructure/persistence/sqlite.d.ts.map +1 -1
- package/dist/infrastructure/persistence/sqlite.js +5 -1
- package/dist/infrastructure/persistence/sqlite.js.map +1 -1
- package/dist/infrastructure/persistence/sqliteBatch.d.ts +9 -4
- package/dist/infrastructure/persistence/sqliteBatch.d.ts.map +1 -1
- package/dist/infrastructure/persistence/sqliteBatch.js +38 -21
- package/dist/infrastructure/persistence/sqliteBatch.js.map +1 -1
- package/dist/infrastructure/persistence/sqliteSerializer.d.ts.map +1 -1
- package/dist/infrastructure/persistence/sqliteSerializer.js +14 -0
- package/dist/infrastructure/persistence/sqliteSerializer.js.map +1 -1
- package/dist/infrastructure/persistence/statements.d.ts +1 -1
- package/dist/infrastructure/persistence/statements.d.ts.map +1 -1
- package/dist/infrastructure/persistence/statements.js +3 -2
- package/dist/infrastructure/persistence/statements.js.map +1 -1
- package/dist/infrastructure/scheduler/cronScheduler.d.ts +7 -0
- package/dist/infrastructure/scheduler/cronScheduler.d.ts.map +1 -1
- package/dist/infrastructure/scheduler/cronScheduler.js +46 -12
- package/dist/infrastructure/scheduler/cronScheduler.js.map +1 -1
- package/dist/infrastructure/server/handlers/core.d.ts.map +1 -1
- package/dist/infrastructure/server/handlers/core.js +26 -19
- package/dist/infrastructure/server/handlers/core.js.map +1 -1
- package/dist/infrastructure/server/handlers/query.d.ts.map +1 -1
- package/dist/infrastructure/server/handlers/query.js +1 -16
- package/dist/infrastructure/server/handlers/query.js.map +1 -1
- package/dist/infrastructure/server/http.d.ts.map +1 -1
- package/dist/infrastructure/server/http.js +27 -2
- package/dist/infrastructure/server/http.js.map +1 -1
- package/dist/infrastructure/server/protocol.d.ts +15 -1
- package/dist/infrastructure/server/protocol.d.ts.map +1 -1
- package/dist/infrastructure/server/protocol.js +37 -3
- package/dist/infrastructure/server/protocol.js.map +1 -1
- package/dist/infrastructure/server/rateLimiter.d.ts.map +1 -1
- package/dist/infrastructure/server/rateLimiter.js +5 -3
- package/dist/infrastructure/server/rateLimiter.js.map +1 -1
- package/dist/infrastructure/server/tcp.d.ts +8 -10
- package/dist/infrastructure/server/tcp.d.ts.map +1 -1
- package/dist/infrastructure/server/tcp.js +87 -46
- package/dist/infrastructure/server/tcp.js.map +1 -1
- package/dist/main.js +7 -6
- package/dist/main.js.map +1 -1
- package/dist/shared/lock.d.ts +1 -1
- package/dist/shared/lock.d.ts.map +1 -1
- package/dist/shared/lock.js +6 -4
- package/dist/shared/lock.js.map +1 -1
- package/dist/shared/lru.d.ts +51 -0
- package/dist/shared/lru.d.ts.map +1 -1
- package/dist/shared/lru.js +89 -3
- package/dist/shared/lru.js.map +1 -1
- package/dist/shared/skipList.d.ts +10 -2
- package/dist/shared/skipList.d.ts.map +1 -1
- package/dist/shared/skipList.js +22 -1
- package/dist/shared/skipList.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/tcp/lineBuffer.d.ts +0 -17
- package/dist/client/tcp/lineBuffer.d.ts.map +0 -1
- package/dist/client/tcp/lineBuffer.js +0 -32
- 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:
|
|
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
|
|
65
|
-
removeOnFail
|
|
66
|
-
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:
|
|
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
|
-
|
|
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
|
|
111
|
-
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(
|
|
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:
|
|
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:
|
|
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(
|
|
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:
|
|
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:
|
|
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
|
}
|