@anishhs/retryq 1.1.0 → 1.2.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/README.md +142 -19
- package/dist/cjs/index.d.ts +9 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +13 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/manager.d.ts +139 -0
- package/dist/cjs/manager.d.ts.map +1 -0
- package/dist/cjs/manager.js +431 -0
- package/dist/cjs/manager.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/types.d.ts +237 -0
- package/dist/cjs/types.d.ts.map +1 -0
- package/dist/cjs/types.js +3 -0
- package/dist/cjs/types.js.map +1 -0
- package/dist/cjs/utils.d.ts +43 -0
- package/dist/cjs/utils.d.ts.map +1 -0
- package/dist/cjs/utils.js +71 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/cjs/validation.d.ts +37 -0
- package/dist/cjs/validation.d.ts.map +1 -0
- package/dist/cjs/validation.js +69 -0
- package/dist/cjs/validation.js.map +1 -0
- package/dist/esm/index.d.ts +9 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +8 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/manager.d.ts +139 -0
- package/dist/esm/manager.d.ts.map +1 -0
- package/dist/esm/manager.js +427 -0
- package/dist/esm/manager.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/types.d.ts +237 -0
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +2 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/utils.d.ts +43 -0
- package/dist/esm/utils.d.ts.map +1 -0
- package/dist/esm/utils.js +64 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/esm/validation.d.ts +37 -0
- package/dist/esm/validation.d.ts.map +1 -0
- package/dist/esm/validation.js +65 -0
- package/dist/esm/validation.js.map +1 -0
- package/package.json +29 -12
- package/dist/index.d.ts +0 -85
- package/dist/index.js +0 -293
- package/dist/index.js.map +0 -1
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
2
|
+
import { clamp, randomId, RetryQTimeoutError, sleep } from "./utils.js";
|
|
3
|
+
import { resolveOptions } from "./validation.js";
|
|
4
|
+
/**
|
|
5
|
+
* In-memory retry queue manager with concurrency control, priority scheduling,
|
|
6
|
+
* exponential backoff with jitter, lifecycle events, cooperative/force
|
|
7
|
+
* cancellation, and bounded job history.
|
|
8
|
+
*
|
|
9
|
+
* The manager extends {@link EventEmitter}; subscribe to `retry`, `success`,
|
|
10
|
+
* `failure`, `cancel`, and `idle` events (see {@link RetryQEvents}).
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* const q = new RetryQManager({ maxConcurrent: 3 });
|
|
15
|
+
* q.on("failure", ({ job, error }) => console.error(job.label, error));
|
|
16
|
+
*
|
|
17
|
+
* const job = q.createJob(async (signal) => {
|
|
18
|
+
* const res = await fetch("https://api.example.com", { signal });
|
|
19
|
+
* if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
20
|
+
* return res.json();
|
|
21
|
+
* }, { retries: 5, shouldRetry: (e) => !`${e}`.includes("404") });
|
|
22
|
+
*
|
|
23
|
+
* await job.promise;
|
|
24
|
+
* await q.onIdle();
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export class RetryQManager extends EventEmitter {
|
|
28
|
+
/**
|
|
29
|
+
* @param config - Manager configuration, or a number for `maxConcurrent`
|
|
30
|
+
* (legacy form, kept for backwards compatibility).
|
|
31
|
+
*/
|
|
32
|
+
constructor(config = {}) {
|
|
33
|
+
super();
|
|
34
|
+
this.pendingQueue = [];
|
|
35
|
+
this.runningJobs = new Map();
|
|
36
|
+
this.failedJobs = new Map();
|
|
37
|
+
this.completedJobs = new Map();
|
|
38
|
+
this.cancelledJobs = new Map();
|
|
39
|
+
this.registry = new Map();
|
|
40
|
+
/** Cleanup callbacks (e.g. external-signal listener removal) keyed by job id. */
|
|
41
|
+
this.cleanups = new Map();
|
|
42
|
+
/** Resolvers waiting for the queue to become idle. */
|
|
43
|
+
this.idleWaiters = [];
|
|
44
|
+
/** Tracks idle state so the `idle` event only fires on transition. */
|
|
45
|
+
this.wasIdle = true;
|
|
46
|
+
// Support legacy number parameter for backwards compatibility
|
|
47
|
+
if (typeof config === "number") {
|
|
48
|
+
this.maxConcurrent = config;
|
|
49
|
+
this.maxHistorySize = 1000;
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
this.maxConcurrent = config.maxConcurrent ?? Infinity;
|
|
53
|
+
this.maxHistorySize = config.maxHistorySize ?? 1000;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
on(event, listener) {
|
|
57
|
+
return super.on(event, listener);
|
|
58
|
+
}
|
|
59
|
+
once(event, listener) {
|
|
60
|
+
return super.once(event, listener);
|
|
61
|
+
}
|
|
62
|
+
off(event, listener) {
|
|
63
|
+
return super.off(event, listener);
|
|
64
|
+
}
|
|
65
|
+
emit(event, ...args) {
|
|
66
|
+
return super.emit(event, ...args);
|
|
67
|
+
}
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Public API
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
/**
|
|
72
|
+
* Create and immediately enqueue a job.
|
|
73
|
+
*
|
|
74
|
+
* @typeParam T - Resolved value produced by `fn`.
|
|
75
|
+
* @param fn - Async function to run. Receives an {@link AbortSignal} that
|
|
76
|
+
* aborts on force-cancellation or attempt/`maxTime` timeout.
|
|
77
|
+
* @param options - Per-job configuration (see {@link RetryQJobOptions}).
|
|
78
|
+
* @returns The created {@link RetryQJob}. Await `job.promise` for the result.
|
|
79
|
+
* @throws {Error} If any option fails validation.
|
|
80
|
+
*/
|
|
81
|
+
createJob(fn, options = {}) {
|
|
82
|
+
const resolved = resolveOptions(options);
|
|
83
|
+
const id = randomId();
|
|
84
|
+
// Internal AbortController drives force cancellation and timeouts.
|
|
85
|
+
const abortController = new AbortController();
|
|
86
|
+
// Link an external signal to the internal controller, and remember how to
|
|
87
|
+
// detach the listener once the job settles (prevents listener leaks).
|
|
88
|
+
if (options.signal) {
|
|
89
|
+
const external = options.signal;
|
|
90
|
+
const onExternalAbort = () => {
|
|
91
|
+
if (!abortController.signal.aborted) {
|
|
92
|
+
abortController.abort(external.reason);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
if (external.aborted) {
|
|
96
|
+
onExternalAbort();
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
external.addEventListener("abort", onExternalAbort, { once: true });
|
|
100
|
+
this.cleanups.set(id, () => external.removeEventListener("abort", onExternalAbort));
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const job = {
|
|
104
|
+
id,
|
|
105
|
+
label: options.label || id,
|
|
106
|
+
state: "pending",
|
|
107
|
+
priority: resolved.priority,
|
|
108
|
+
retriesLeft: resolved.retries + 1, // +1 for the initial attempt
|
|
109
|
+
promise: Promise.resolve(), // placeholder, replaced below
|
|
110
|
+
cancel: (force) => this.cancelJob(id, force),
|
|
111
|
+
fn,
|
|
112
|
+
options: { ...options, ...resolved },
|
|
113
|
+
createdAt: Date.now(),
|
|
114
|
+
abortController,
|
|
115
|
+
};
|
|
116
|
+
// Enqueue BEFORE starting execution so state is always consistent.
|
|
117
|
+
this.pendingQueue.push(job);
|
|
118
|
+
this._sortQueue();
|
|
119
|
+
this.wasIdle = false;
|
|
120
|
+
job.promise = this._runJob(job);
|
|
121
|
+
// Prevent unhandled rejections if the consumer never attaches `.catch()`;
|
|
122
|
+
// the error is still available via `job.error`.
|
|
123
|
+
job.promise.catch(() => { });
|
|
124
|
+
this._processQueue();
|
|
125
|
+
return job;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Cancel a pending or running job.
|
|
129
|
+
*
|
|
130
|
+
* Cooperative (default) cancellation stops future retries and interrupts the
|
|
131
|
+
* delay between them. Force cancellation additionally aborts the in-flight
|
|
132
|
+
* attempt via its {@link AbortSignal}.
|
|
133
|
+
*
|
|
134
|
+
* @param id - Id of the job to cancel.
|
|
135
|
+
* @param force - When `true`, abort in-progress execution. Defaults to `false`.
|
|
136
|
+
*/
|
|
137
|
+
cancelJob(id, force = false) {
|
|
138
|
+
const job = this.runningJobs.get(id) || this.pendingQueue.find((j) => j.id === id);
|
|
139
|
+
if (!job)
|
|
140
|
+
return;
|
|
141
|
+
job.state = "cancelled";
|
|
142
|
+
job.error = new Error("Job cancelled");
|
|
143
|
+
job.finishedAt = Date.now();
|
|
144
|
+
if (force && job.abortController && !job.abortController.signal.aborted) {
|
|
145
|
+
job.abortController.abort(new Error("Job forcefully cancelled"));
|
|
146
|
+
}
|
|
147
|
+
this.runningJobs.delete(id);
|
|
148
|
+
this.pendingQueue = this.pendingQueue.filter((j) => j.id !== id);
|
|
149
|
+
this._evictOldest(this.cancelledJobs);
|
|
150
|
+
this.cancelledJobs.set(id, job);
|
|
151
|
+
const cancelFn = this.registry.get(id);
|
|
152
|
+
cancelFn?.cancelSleep?.();
|
|
153
|
+
this.registry.delete(id);
|
|
154
|
+
this._runCleanup(id);
|
|
155
|
+
job.options.onCancel?.();
|
|
156
|
+
this.emit("cancel", { job });
|
|
157
|
+
this._processQueue();
|
|
158
|
+
this._checkIdle();
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Returns a promise that resolves when the queue is fully idle — no pending
|
|
162
|
+
* and no running jobs. Resolves immediately if already idle.
|
|
163
|
+
*
|
|
164
|
+
* @returns A promise that resolves on idle.
|
|
165
|
+
*/
|
|
166
|
+
onIdle() {
|
|
167
|
+
if (this._isIdle())
|
|
168
|
+
return Promise.resolve();
|
|
169
|
+
return new Promise((resolve) => this.idleWaiters.push(resolve));
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Alias for {@link RetryQManager.onIdle}.
|
|
173
|
+
* @returns A promise that resolves when the queue is idle.
|
|
174
|
+
*/
|
|
175
|
+
drain() {
|
|
176
|
+
return this.onIdle();
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Clear retained job history.
|
|
180
|
+
*
|
|
181
|
+
* @param state - Optional terminal state to clear (`completed`, `failed`, or
|
|
182
|
+
* `cancelled`). When omitted, all history is cleared.
|
|
183
|
+
*/
|
|
184
|
+
clearHistory(state) {
|
|
185
|
+
if (!state || state === "failed")
|
|
186
|
+
this.failedJobs.clear();
|
|
187
|
+
if (!state || state === "completed")
|
|
188
|
+
this.completedJobs.clear();
|
|
189
|
+
if (!state || state === "cancelled")
|
|
190
|
+
this.cancelledJobs.clear();
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Snapshot of all jobs grouped by state.
|
|
194
|
+
* @returns A {@link JobListSnapshot}.
|
|
195
|
+
*/
|
|
196
|
+
listJobs() {
|
|
197
|
+
return {
|
|
198
|
+
pending: this.pendingQueue.map((j) => this._jobSummary(j)),
|
|
199
|
+
running: Array.from(this.runningJobs.values()).map((j) => this._jobSummary(j)),
|
|
200
|
+
failed: Array.from(this.failedJobs.values()).map((j) => this._jobSummary(j)),
|
|
201
|
+
completed: Array.from(this.completedJobs.values()).map((j) => this._jobSummary(j)),
|
|
202
|
+
cancelled: Array.from(this.cancelledJobs.values()).map((j) => this._jobSummary(j)),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Find a job by id across every state.
|
|
207
|
+
* @param id - Job id.
|
|
208
|
+
* @returns The job, or `null` if not found.
|
|
209
|
+
*/
|
|
210
|
+
findJobById(id) {
|
|
211
|
+
return (this.runningJobs.get(id) ||
|
|
212
|
+
this.pendingQueue.find((j) => j.id === id) ||
|
|
213
|
+
this.failedJobs.get(id) ||
|
|
214
|
+
this.completedJobs.get(id) ||
|
|
215
|
+
this.cancelledJobs.get(id) ||
|
|
216
|
+
null);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Find all jobs (across every state) with a matching label.
|
|
220
|
+
* @param label - Label to match.
|
|
221
|
+
* @returns Matching jobs.
|
|
222
|
+
*/
|
|
223
|
+
findJobsByLabel(label) {
|
|
224
|
+
const all = [
|
|
225
|
+
...Array.from(this.runningJobs.values()),
|
|
226
|
+
...this.pendingQueue,
|
|
227
|
+
...Array.from(this.failedJobs.values()),
|
|
228
|
+
...Array.from(this.completedJobs.values()),
|
|
229
|
+
...Array.from(this.cancelledJobs.values()),
|
|
230
|
+
];
|
|
231
|
+
return all.filter((j) => j.label === label);
|
|
232
|
+
}
|
|
233
|
+
// ---------------------------------------------------------------------------
|
|
234
|
+
// Internals
|
|
235
|
+
// ---------------------------------------------------------------------------
|
|
236
|
+
/** Evict the oldest entry from a history map when it reaches the size cap. */
|
|
237
|
+
_evictOldest(map) {
|
|
238
|
+
if (map.size >= this.maxHistorySize) {
|
|
239
|
+
const oldest = map.keys().next().value;
|
|
240
|
+
if (oldest)
|
|
241
|
+
map.delete(oldest);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
/** Sort the pending queue by descending priority (stable: FIFO within a tier). */
|
|
245
|
+
_sortQueue() {
|
|
246
|
+
this.pendingQueue.sort((a, b) => b.priority - a.priority);
|
|
247
|
+
}
|
|
248
|
+
/** Promote pending jobs into running while capacity allows (synchronous). */
|
|
249
|
+
_processQueue() {
|
|
250
|
+
while (this.runningJobs.size < this.maxConcurrent &&
|
|
251
|
+
this.pendingQueue.length > 0) {
|
|
252
|
+
const job = this.pendingQueue.shift();
|
|
253
|
+
this.runningJobs.set(job.id, job);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
_isIdle() {
|
|
257
|
+
return this.pendingQueue.length === 0 && this.runningJobs.size === 0;
|
|
258
|
+
}
|
|
259
|
+
/** Resolve idle waiters and emit `idle` once when the queue drains. */
|
|
260
|
+
_checkIdle() {
|
|
261
|
+
if (!this._isIdle()) {
|
|
262
|
+
this.wasIdle = false;
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
if (this.wasIdle)
|
|
266
|
+
return; // already idle; don't fire twice
|
|
267
|
+
this.wasIdle = true;
|
|
268
|
+
const waiters = this.idleWaiters;
|
|
269
|
+
this.idleWaiters = [];
|
|
270
|
+
for (const resolve of waiters)
|
|
271
|
+
resolve();
|
|
272
|
+
this.emit("idle");
|
|
273
|
+
}
|
|
274
|
+
/** Run and remove a job's cleanup callback, if any. */
|
|
275
|
+
_runCleanup(id) {
|
|
276
|
+
const cleanup = this.cleanups.get(id);
|
|
277
|
+
if (cleanup) {
|
|
278
|
+
cleanup();
|
|
279
|
+
this.cleanups.delete(id);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Execute a single attempt, bounded by `timeoutMs`. A per-attempt
|
|
284
|
+
* AbortController is linked to the job's controller so force-cancellation
|
|
285
|
+
* still propagates, while a timeout aborts only this attempt (leaving the job
|
|
286
|
+
* free to retry). Uses `Promise.race` so the loop advances even if `fn`
|
|
287
|
+
* ignores the signal.
|
|
288
|
+
*/
|
|
289
|
+
_runAttempt(job, timeoutMs) {
|
|
290
|
+
const jobSignal = job.abortController?.signal;
|
|
291
|
+
if (!isFinite(timeoutMs)) {
|
|
292
|
+
return job.fn(jobSignal);
|
|
293
|
+
}
|
|
294
|
+
const attemptController = new AbortController();
|
|
295
|
+
const onJobAbort = () => attemptController.abort(jobSignal?.reason);
|
|
296
|
+
if (jobSignal) {
|
|
297
|
+
if (jobSignal.aborted) {
|
|
298
|
+
attemptController.abort(jobSignal.reason);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
jobSignal.addEventListener("abort", onJobAbort, { once: true });
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
let timer;
|
|
305
|
+
const timeout = new Promise((_, reject) => {
|
|
306
|
+
timer = setTimeout(() => {
|
|
307
|
+
attemptController.abort(new RetryQTimeoutError(timeoutMs));
|
|
308
|
+
reject(new RetryQTimeoutError(timeoutMs));
|
|
309
|
+
}, timeoutMs);
|
|
310
|
+
});
|
|
311
|
+
return Promise.race([job.fn(attemptController.signal), timeout]).finally(() => {
|
|
312
|
+
clearTimeout(timer);
|
|
313
|
+
jobSignal?.removeEventListener("abort", onJobAbort);
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
/** Core retry loop for a single job. */
|
|
317
|
+
async _runJob(job) {
|
|
318
|
+
// Wait until _processQueue() has granted this job a concurrency slot.
|
|
319
|
+
while (!this.runningJobs.has(job.id)) {
|
|
320
|
+
if (job.state === "cancelled") {
|
|
321
|
+
throw job.error ?? new Error("Job cancelled");
|
|
322
|
+
}
|
|
323
|
+
if (job.abortController?.signal.aborted) {
|
|
324
|
+
job.state = "cancelled";
|
|
325
|
+
job.error = new Error("Job cancelled via abort signal");
|
|
326
|
+
throw job.error;
|
|
327
|
+
}
|
|
328
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
329
|
+
}
|
|
330
|
+
job.state = "running";
|
|
331
|
+
job.startedAt = Date.now();
|
|
332
|
+
const cancelFn = () => { };
|
|
333
|
+
this.registry.set(job.id, cancelFn);
|
|
334
|
+
const { delay, backoff, maxTime, maxDelay, jitter, attemptTimeout } = resolveOptions(job.options);
|
|
335
|
+
let currentDelay = delay;
|
|
336
|
+
let attempt = 0;
|
|
337
|
+
try {
|
|
338
|
+
while (job.retriesLeft > 0) {
|
|
339
|
+
if (job.state === "cancelled")
|
|
340
|
+
break;
|
|
341
|
+
if (job.abortController?.signal.aborted) {
|
|
342
|
+
job.state = "cancelled";
|
|
343
|
+
job.error = new Error("Job cancelled via abort signal");
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
const elapsed = Date.now() - (job.startedAt ?? Date.now());
|
|
347
|
+
const remaining = maxTime - elapsed;
|
|
348
|
+
if (remaining <= 0)
|
|
349
|
+
break; // overall time budget exhausted
|
|
350
|
+
attempt++;
|
|
351
|
+
const effectiveTimeout = Math.min(attemptTimeout, remaining);
|
|
352
|
+
try {
|
|
353
|
+
const result = await this._runAttempt(job, effectiveTimeout);
|
|
354
|
+
if (job.state === "cancelled")
|
|
355
|
+
break;
|
|
356
|
+
job.state = "completed";
|
|
357
|
+
job.finishedAt = Date.now();
|
|
358
|
+
this._evictOldest(this.completedJobs);
|
|
359
|
+
this.completedJobs.set(job.id, job);
|
|
360
|
+
job.options.onSuccess?.(result);
|
|
361
|
+
this.emit("success", { job, result });
|
|
362
|
+
return result;
|
|
363
|
+
}
|
|
364
|
+
catch (err) {
|
|
365
|
+
job.retriesLeft--;
|
|
366
|
+
job.error = err;
|
|
367
|
+
if (job.state === "cancelled")
|
|
368
|
+
break;
|
|
369
|
+
if (job.abortController?.signal.aborted) {
|
|
370
|
+
job.state = "cancelled";
|
|
371
|
+
break;
|
|
372
|
+
}
|
|
373
|
+
// Honour the retry predicate, if supplied.
|
|
374
|
+
if (job.options.shouldRetry && !job.options.shouldRetry(err, attempt)) {
|
|
375
|
+
break;
|
|
376
|
+
}
|
|
377
|
+
if (job.retriesLeft <= 0)
|
|
378
|
+
break;
|
|
379
|
+
// Compute the next delay: cap, jitter, then clamp to remaining budget.
|
|
380
|
+
const elapsedNow = Date.now() - (job.startedAt ?? Date.now());
|
|
381
|
+
const cappedDelay = Math.min(currentDelay, maxDelay);
|
|
382
|
+
const jitterAmount = cappedDelay * jitter;
|
|
383
|
+
const nextDelay = clamp(cappedDelay + (Math.random() * 2 - 1) * jitterAmount, 0, Math.max(0, maxTime - elapsedNow));
|
|
384
|
+
const info = {
|
|
385
|
+
attempt,
|
|
386
|
+
error: err,
|
|
387
|
+
nextDelay,
|
|
388
|
+
retriesLeft: job.retriesLeft,
|
|
389
|
+
};
|
|
390
|
+
job.options.onRetry?.(info);
|
|
391
|
+
this.emit("retry", { job, info });
|
|
392
|
+
if (nextDelay > 0)
|
|
393
|
+
await sleep(nextDelay, cancelFn);
|
|
394
|
+
currentDelay *= backoff;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
// Loop exited without a successful return.
|
|
398
|
+
if (job.state === "cancelled") {
|
|
399
|
+
throw job.error ?? new Error("Job cancelled");
|
|
400
|
+
}
|
|
401
|
+
job.state = "failed";
|
|
402
|
+
job.finishedAt = Date.now();
|
|
403
|
+
this._evictOldest(this.failedJobs);
|
|
404
|
+
this.failedJobs.set(job.id, job);
|
|
405
|
+
job.options.onFailure?.(job.error);
|
|
406
|
+
this.emit("failure", { job, error: job.error });
|
|
407
|
+
throw job.error ?? new Error("Job failed");
|
|
408
|
+
}
|
|
409
|
+
finally {
|
|
410
|
+
this.runningJobs.delete(job.id);
|
|
411
|
+
this.registry.delete(job.id);
|
|
412
|
+
this._runCleanup(job.id);
|
|
413
|
+
this._processQueue();
|
|
414
|
+
this._checkIdle();
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
_jobSummary(job) {
|
|
418
|
+
return {
|
|
419
|
+
id: job.id,
|
|
420
|
+
label: job.label,
|
|
421
|
+
state: job.state,
|
|
422
|
+
retriesLeft: job.retriesLeft,
|
|
423
|
+
priority: job.priority,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/manager.ts"],"names":[],"mappings":"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"}
|