You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Add dead-letter job handling and related tests
- Introduced the `deadLetterJobType` option in the `JobOptions` interface to specify a destination for jobs that exhaust their retry attempts.
- Updated the `JobRecord` interface to include fields for tracking dead-letter job metadata, such as `deadLetteredAt` and `deadLetterJobId`.
- Enhanced documentation to explain the dead-letter routing feature, including examples of configuration and payload structure.
- Implemented logic in both PostgreSQL and Redis backends to create dead-letter jobs when retries are exhausted.
- Added tests to verify the correct behavior of dead-letter routing and job reprocessing.
These changes improve error handling and job management in DataQueue, providing users with a robust mechanism for dealing with failed jobs.
* Enhance testing and coverage reporting in CI workflow
- Updated the CI workflow to include coverage reporting for unit and E2E tests, utilizing Codecov for coverage uploads.
- Added new scripts for running tests with coverage in both the dataqueue and E2E applications.
- Configured Vite to support coverage reporting with the V8 provider, generating reports in multiple formats.
- Updated `.gitignore` to exclude coverage directories from version control.
These changes improve test visibility and ensure comprehensive coverage reporting across the project.
* Update Codecov action to v5 and add token for coverage uploads in CI workflow
- Upgraded the Codecov GitHub Action from v4 to v5 for improved functionality.
- Added a token for secure coverage uploads for both unit and E2E tests, enhancing security and reliability in the CI process.
These changes ensure better integration with Codecov and improve coverage reporting in the CI workflow.
* update readme
---------
Co-authored-by: Nico Prananta <311343+nicnocquee@users.noreply.github.com>
A lightweight, Redis or PostgreSQL job queue for Node.js/TypeScript projects. Schedule, process, and manage background jobs with ease. Perfect for web apps (Next.js, etc.) deployed to serverless platforms like Vercel, AWS Lambda, etc.
Copy file name to clipboardExpand all lines: apps/docs/public/llms-full.txt
+44-4Lines changed: 44 additions & 4 deletions
Original file line number
Diff line number
Diff line change
@@ -199,6 +199,7 @@ The `JobOptions` interface defines the options for creating a new job in the que
199
199
200
200
- `tags?`: _string[]_ — Tags for this job. Used for grouping, searching, or batch operations.
201
201
- `idempotencyKey?`: _string_ — Optional idempotency key. When provided, ensures that only one job exists for a given key. If a job with the same key already exists, `addJob` returns the existing job's ID instead of creating a duplicate. See [Idempotency](/usage/add-job#idempotency) for details.
202
+
- `deadLetterJobType?`: _string_ — Optional dead-letter destination job type. When the job exhausts retries, DataQueue creates a new pending job in this job type with an envelope payload containing source metadata, original payload, and failure context.
202
203
203
204
## Example
204
205
@@ -213,6 +214,7 @@ const job = {
213
214
forceKillOnTimeout: false, // Use graceful shutdown (default)
214
215
tags: ['welcome', 'user'], // tags for grouping/searching
215
216
idempotencyKey: 'welcome-email-user-123', // prevent duplicate jobs
retryDelay?: number; // Base delay between retries in seconds (default: 60)
336
338
retryBackoff?: boolean; // Use exponential backoff (default: true)
337
339
retryDelayMax?: number; // Max delay cap in seconds (default: none)
340
+
deadLetterJobType?: string; // Route exhausted failures to this job type
338
341
group?: { id: string; tier?: string }; // Optional group for global concurrency limits
339
342
}
340
343
```
341
344
342
345
- `retryDelay` - Base delay between retries in seconds. When `retryBackoff` is true, this is the base for exponential backoff (`retryDelay * 2^attempts`). When false, retries use this fixed delay. Default: `60`.
343
346
- `retryBackoff` - Whether to use exponential backoff. When true, delay doubles with each attempt and includes jitter. Default: `true`.
344
347
- `retryDelayMax` - Maximum delay cap in seconds. Only meaningful when `retryBackoff` is true. No limit when omitted.
348
+
- `deadLetterJobType` - Optional dead-letter destination. When retries are exhausted, a new pending job is created in this job type with an envelope payload (`originalJob`, `originalPayload`, `failure`).
345
349
- `group` - Optional grouping metadata. Use `group.id` to enforce global per-group limits with `ProcessorOptions.groupConcurrency`. `group.tier` is reserved for future policies.
346
350
347
351
#### AddJobOptions
@@ -497,10 +501,11 @@ interface EditJobOptions {
497
501
retryDelay?: number | null;
498
502
retryBackoff?: boolean | null;
499
503
retryDelayMax?: number | null;
504
+
deadLetterJobType?: string | null;
500
505
}
501
506
```
502
507
503
-
All fields are optional - only provided fields will be updated. Note that `jobType` cannot be changed. Set retry fields to `null` to revert to legacy default behavior.
508
+
All fields are optional - only provided fields will be updated. Note that `jobType` cannot be changed. Set retry fields to `null` to revert to legacy default behavior. Set `deadLetterJobType` to `null` to clear dead-letter routing for pending jobs.
504
509
505
510
#### Example
506
511
@@ -858,7 +863,7 @@ The `JobRecord` interface represents a job stored in the queue, including its st
- `updated_at`: _Date_ — When the job was last updated.
@@ -890,6 +895,9 @@ The `JobRecord` interface represents a job stored in the queue, including its st
890
895
- `idempotencyKey?`: _string | null_ — The idempotency key for this job, if one was provided when the job was created.
891
896
- `progress?`: _number | null_ — Progress percentage (0–100) reported by the handler via `ctx.setProgress()`. `null` if no progress has been reported. See [Progress Tracking](/usage/progress-tracking).
892
897
- `output?`: _unknown_ — Handler output stored via `ctx.setOutput(data)` or by returning a value from the handler. `null` if no output has been stored. See [Job Output](/usage/job-output).
898
+
- `deadLetterJobType?`: _string | null_ — Configured dead-letter destination job type for this job.
899
+
- `deadLetteredAt?`: _Date | null_ — Timestamp when this job was routed to a dead-letter job.
900
+
- `deadLetterJobId?`: _number | null_ — Linked dead-letter job ID created when retries were exhausted.
893
901
894
902
## Example
895
903
@@ -1994,8 +2002,9 @@ Type handlers as `JobHandlers<PayloadMap>` — TypeScript enforces a handler for
1994
2002
1. Creating initJobQueue per request (creates a DB pool each time)
1995
2003
2. Missing handler for a job type (fails with NoHandler)
1996
2004
3. Not checking signal.aborted in long handlers
1997
-
4. Forgetting reclaimStuckJobs() — crashed workers leave jobs stuck
@@ -3059,6 +3068,37 @@ A job handler can fail for many reasons, such as a bug in the code or running ou
3059
3068
3060
3069
When a job fails, it is marked as `failed` and retried up to `maxAttempts` times (default: 3). You can view the error history for a job in its `errorHistory` field.
3061
3070
3071
+
## Dead-letter queues
3072
+
3073
+
You can route permanently failed jobs to a dead-letter job type using `deadLetterJobType`.
3074
+
3075
+
When a job exhausts retries (`attempts >= maxAttempts`), DataQueue:
3076
+
3077
+
1. Keeps the source job as `failed`.
3078
+
2. Creates a new pending dead-letter job in `deadLetterJobType`.
3079
+
3. Stores linkage metadata on the source job (`deadLetteredAt`, `deadLetterJobId`).
0 commit comments