Description
Currently, when a deferred task exhausts all its retry attempts, it is silently discarded. There is no record of what failed, why it failed, or what arguments it was called with. This makes it difficult to diagnose recurring issues and impossible to recover failed work without re-triggering it from scratch.
A dead letter queue (DLQ) would capture tasks that have exhausted all retries, preserving the task class, arguments, exception details, and retry history. This gives operators visibility into persistent failures and the ability to investigate and replay failed tasks.
Implementation
The DLQ should store:
- Task class name — which task failed.
- Task arguments — the arguments passed to
perform.
- Last exception — the exception class, message, and backtrace from the final attempt.
- Retry count — how many times the task was attempted.
- Timestamps — when the task was originally enqueued (if available) and when it was moved to the DLQ.
Storage
Since Rage::Deferred already uses a write-ahead log (WAL) with no external dependencies, the DLQ should follow the same philosophy. A disk-based approach (e.g. a separate file) would be a natural fit. Consider whether the DLQ should share the WAL's format, or if a substitute-all-on-write approach would fit better.
API surface
At a minimum, operators need a way to:
- List dead-lettered tasks.
- Inspect a specific task's details.
- Retry one or more dead-lettered tasks (re-enqueue them).
- Delete tasks from the DLQ.
Whether this is exposed as a Ruby API, a Rake task, or both is a design decision worth discussing.
Tips
- Review the Deferred docs — especially the retry mechanism and WAL sections — to understand the current behavior when tasks fail.
- Look at how the existing WAL persistence works in the codebase to inform the DLQ storage design.
- Check the architecture doc to see how Rage's core components interact and to understand the design principles.
- Read the contributing guide for coding conventions and design principles used across the codebase.
- Before starting the implementation, please share your proposed design approach. Discussing the approach early will drastically increase the chances of acceptance and help avoid rework.
- Feel free to ask any questions or request help in the comments below!
Description
Currently, when a deferred task exhausts all its retry attempts, it is silently discarded. There is no record of what failed, why it failed, or what arguments it was called with. This makes it difficult to diagnose recurring issues and impossible to recover failed work without re-triggering it from scratch.
A dead letter queue (DLQ) would capture tasks that have exhausted all retries, preserving the task class, arguments, exception details, and retry history. This gives operators visibility into persistent failures and the ability to investigate and replay failed tasks.
Implementation
The DLQ should store:
perform.Storage
Since
Rage::Deferredalready uses a write-ahead log (WAL) with no external dependencies, the DLQ should follow the same philosophy. A disk-based approach (e.g. a separate file) would be a natural fit. Consider whether the DLQ should share the WAL's format, or if a substitute-all-on-write approach would fit better.API surface
At a minimum, operators need a way to:
Whether this is exposed as a Ruby API, a Rake task, or both is a design decision worth discussing.
Tips