@zudojs/queue 1.4.1 → 1.5.1
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
CHANGED
|
@@ -165,6 +165,32 @@ queue.events?.on("job:completed", ({ job, result }) => {
|
|
|
165
165
|
});
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
+
`job:failed` fires on **every** failed attempt, not only the last, and a
|
|
169
|
+
processor failure reports `job.state === "failed"` on a retryable attempt
|
|
170
|
+
and on the final one alike, with `job.attempt` still counting the attempts
|
|
171
|
+
before this one. What follows tells them apart:
|
|
172
|
+
|
|
173
|
+
| Attempt | `job:failed` `job.state` | Then |
|
|
174
|
+
|---------|--------------------------|------|
|
|
175
|
+
| Retryable (attempts left) | `"failed"` | `job:retrying` (`"retrying"`); after the backoff the job is `"waiting"` again |
|
|
176
|
+
| Final (attempts exhausted) | `"failed"` | `job:dead-lettered` (`"dead_letter"`) |
|
|
177
|
+
| Stalled, reclaimed | `"active"` (as found), `JobStalledError` | the job is `"waiting"` again |
|
|
178
|
+
| Stalled `maxStalledCount` times | `"dead_letter"`, `JobStalledError` | `job:dead-lettered` |
|
|
179
|
+
|
|
180
|
+
To alert only on dead letters, subscribe to `job:dead-lettered`. It fires once
|
|
181
|
+
per job, when the job enters the dead-letter store, with the entry's `error`
|
|
182
|
+
(`JobMaxAttemptsError`, or `JobStalledError` for a stalled job) and `reason`
|
|
183
|
+
(the last attempt's error message, or `"Stalled N time(s)."`):
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
queue.events?.on("job:dead-lettered", ({ job, error, reason }) => {
|
|
187
|
+
alerts.page(`${job.name} ${job.id} dead-lettered: ${reason}`, error);
|
|
188
|
+
});
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
It fires even if a custom `deadLetterStore.add()` rejects, in step with
|
|
192
|
+
`getStats().deadLettered`. Before 1.5.0 there was no dead-letter event.
|
|
193
|
+
|
|
168
194
|
## Workers, timeouts and context
|
|
169
195
|
|
|
170
196
|
**One consumer at a time.** `queue.process()` registers a processor and, by
|
|
@@ -574,16 +574,22 @@ export class InMemoryQueue {
|
|
|
574
574
|
failedAt: new Date().toISOString(),
|
|
575
575
|
});
|
|
576
576
|
this.jobs.set(job.id, deadLettered);
|
|
577
|
+
const reason = `Stalled ${count} time(s).`;
|
|
577
578
|
void this.deadLetterStore
|
|
578
579
|
.add({
|
|
579
580
|
job: deadLettered,
|
|
580
581
|
deadLetterAt: new Date(),
|
|
581
582
|
error,
|
|
582
583
|
attempts: deadLettered.attempt,
|
|
583
|
-
reason
|
|
584
|
+
reason,
|
|
584
585
|
})
|
|
585
586
|
.catch(() => { });
|
|
586
587
|
this.emitter.emit("job:failed", { job: deadLettered, error });
|
|
588
|
+
this.emitter.emit("job:dead-lettered", {
|
|
589
|
+
job: deadLettered,
|
|
590
|
+
error,
|
|
591
|
+
reason,
|
|
592
|
+
});
|
|
587
593
|
this.recordSettled(deadLettered);
|
|
588
594
|
continue;
|
|
589
595
|
}
|
|
@@ -171,6 +171,11 @@ export async function handleJobFailure(job, errorMessage, deps) {
|
|
|
171
171
|
}
|
|
172
172
|
const deadLetterJob = updateJobState(incrementedJob, JobStateEnum.DEAD_LETTER, { error: maxAttemptsError.message });
|
|
173
173
|
jobs.set(job.id, deadLetterJob);
|
|
174
|
+
emitter.emit("job:dead-lettered", {
|
|
175
|
+
job: deadLetterJob,
|
|
176
|
+
error: maxAttemptsError,
|
|
177
|
+
reason: errorMessage,
|
|
178
|
+
});
|
|
174
179
|
deps.onSettled?.(deadLetterJob);
|
|
175
180
|
}
|
|
176
181
|
//# sourceMappingURL=inMemoryQueue.processing.js.map
|
|
@@ -267,6 +267,11 @@ export type QueueEventMap = {
|
|
|
267
267
|
job: Job;
|
|
268
268
|
result: unknown;
|
|
269
269
|
};
|
|
270
|
+
/**
|
|
271
|
+
* An attempt failed. Fires on every failed attempt, retryable or final;
|
|
272
|
+
* `job.state` is `"failed"` for a processor failure either way. Use
|
|
273
|
+
* `job:retrying` or `job:dead-lettered` to tell the two apart.
|
|
274
|
+
*/
|
|
270
275
|
"job:failed": {
|
|
271
276
|
job: Job;
|
|
272
277
|
error: Error;
|
|
@@ -275,6 +280,17 @@ export type QueueEventMap = {
|
|
|
275
280
|
job: Job;
|
|
276
281
|
attempt: number;
|
|
277
282
|
};
|
|
283
|
+
/**
|
|
284
|
+
* The job was moved to the dead-letter store (attempts exhausted, or
|
|
285
|
+
* stalled `maxStalledCount` times). Fires once per job, after the
|
|
286
|
+
* `job:failed` for its last attempt; `job.state` is `"dead_letter"` and
|
|
287
|
+
* `error` / `reason` are the dead-letter entry's.
|
|
288
|
+
*/
|
|
289
|
+
"job:dead-lettered": {
|
|
290
|
+
job: Job;
|
|
291
|
+
error: Error;
|
|
292
|
+
reason?: string;
|
|
293
|
+
};
|
|
278
294
|
/** A running job was aborted from outside — a drain, a close, a cancel. */
|
|
279
295
|
"job:cancelled": {
|
|
280
296
|
job: Job;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zudojs/queue",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "Background job and asynchronous task infrastructure with in-memory and adapter-based queue implementations.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"!dist/.tsbuildinfo"
|
|
26
26
|
],
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@zudojs/errors": "1.3.
|
|
29
|
-
"@zudojs/constants": "1.1.
|
|
30
|
-
"@zudojs/serialization": "1.2.
|
|
28
|
+
"@zudojs/errors": "1.3.2",
|
|
29
|
+
"@zudojs/constants": "1.1.4",
|
|
30
|
+
"@zudojs/serialization": "1.2.3"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"typescript": "7.0.2",
|