ADR-0035: Dead-Letter Queue Safety Controls
Status: Accepted
Date: 2026-06-12
Author: @johalputt
Context
The write queue's dead-letter replay was unbounded. A poison job (e.g., a write job with malformed JSON that always fails) could be replayed indefinitely, consuming worker capacity and filling logs.
Decision
- Add
replay_count(INTEGER, default 0) anddead_reason(TEXT) columns towrite_jobs. - Replay is limited to
MAX_REPLAY_COUNTattempts (default 3, configurable via env). - Replay is batched — maximum
REPLAY_BATCH_LIMIT(default 100) jobs per replay call. - After
MAX_REPLAY_COUNTreplays, the job is quarantined: status set toquarantined,dead_reasonset to"max_replay_count_exceeded", andmetricPoisonJobsQuarantinedincremented. - Quarantined jobs are not processed further. They are retained for manual inspection.
- Backoff is capped at
maxBackoffSeconds = 300(5 minutes) to preventmath.Pow(2, retry)overflow.
Rationale
Without replay limits, a single malformed article write job (e.g., from a corrupt API client) can starve the queue. The quarantine mechanism preserves the job for debugging while protecting worker capacity.
Consequences
- Positive: Poison jobs cannot starve the queue.
- Positive: Dead jobs are retained for inspection, not silently discarded.
- Negative: Quarantined jobs require manual intervention to resolve (either fix the data or delete).