Dead Letter Queue

resilience

Definition

Give the processing path an explicit route for declared failures: a message that cannot be processed — after retries, or on a non-transient error — is negatively acknowledged and persisted to a separate queue or topic, and the main flow's progress marker passes over it. The pattern converts an indefinite blockage (or an indefinite retry loop) into a deferred, inspectable operator decision: dead-lettered items are stored with enough context to be replayed into the main flow (merge) or discarded (purge) later, deliberately, by a human or a tool acting for one.

What the pattern does NOT do is resolve anything: it relocates the cost of a poison pill from every item behind it to an operational backlog with its own ownership question. Two guards keep it honest: the nack must be an explicit signal (a handler that hangs rather than errors needs timeout machinery to convert silence into a decision), and the route must be protected from outages — when the consumer is entirely down, stop delivering rather than dead-lettering healthy traffic, or the DLQ becomes a second copy of the incident. Boundary against Retryable Error Classification: that pattern decides whether an error may be retried; the dead letter queue is where the non-retryable verdicts (and the retry-exhausted) physically go.

When it applies

  • Ordered or windowed consumption where a single unprocessable item blocks or degrades everything behind it
  • At-least-once pipelines where dropping a failed message is unacceptable but blocking on it is worse
  • Any queue whose failure handling currently consists of infinite retries — the DLQ is where the loop is allowed to end

Tradeoffs

  • Deferral is not resolution: the DLQ accumulates an operational backlog that needs owners, tooling, and retention policy or it becomes a write-only graveyard
  • Replay (merge) reintroduces old messages into a flow whose state has moved on — ordering and staleness hazards the original delivery never had
  • The explicit-nack requirement pushes classification work into every consumer: something must decide, per failure, whether this message is dead or merely unlucky

Seen in

  • Uber EngineeringAug 31, 2021

    The Ledger Above the Log: Uber's Kafka Consumer Proxy

    The companion that completes selective acknowledgment's vocabulary: an unprocessable message is negatively acknowledged, persisted to a DLQ topic, and the watermark passes over it — converting an indefinite partition blockage into a deferred operator decision with merge/purge tooling. The circuit breaker guards the pattern's failure mode: when the consumer is entirely down, stop pushing, so an outage doesn't launder healthy messages into the dead letter queue.