Dispatch

Dead Letter Queue

Failed job management, inspection, replay, and purge.

The dead letter queue (DLQ) captures jobs that have permanently failed after exhausting all retry attempts.

How entries are created

When a job's RetryCount reaches MaxRetries and the handler still returns an error, the executor calls dlq.Service.Push to create a DLQ entry preserving the full context:

  • Original job name, queue, and payload
  • Final error message
  • Total retry count and max retries
  • Scope app/org IDs

The job state is set to failed and an ext.JobDLQ event fires.

Listing DLQ entries

entries, err := eng.DLQService().DLQStore().ListDLQ(ctx, dlq.ListOpts{
    Limit:  50,
    Offset: 0,
})

Or use the admin API:

GET /v1/dlq
GET /v1/dlq/:entryId
GET /v1/dlq/count

Replay

Replay re-enqueues a DLQ entry as a new pending job with the original payload. The ReplayedAt field is set on the DLQ entry.

Via admin API:

POST /v1/dlq/:entryId/replay

Purge

Remove all DLQ entries:

POST /v1/dlq/purge

This is destructive and irreversible. Use with caution.

DLQ service

The dlq.Service is accessible via the engine:

svc := eng.DLQService()

// Push is called automatically by the executor.
svc.Push(ctx, failedJob, err)

// Access the store directly for list/count/purge.
svc.DLQStore().ListDLQ(ctx, opts)
svc.DLQStore().PurgeDLQ(ctx)

On this page