← Concepts

阅读中文版本

Dead-Letter Queue

A dead-letter queue isolates messages that repeatedly fail processing, preserving them for diagnosis while the main queue continues to make progress.

messaging

Definition

A dead-letter queue (DLQ) receives messages that a consumer cannot process after a bounded number of attempts or after a non-retryable error. Moving a poison message out of the main queue prevents it from blocking a partition or consuming retry capacity indefinitely. The DLQ is a holding area for diagnosis, repair, and controlled replay, not an automatic discard bin.

Context and scope

DLQs are used with queues and event streams such as SQS, RabbitMQ, Kafka, and cloud pub/sub. They matter when a single malformed or incompatible message can stop an ordered consumer or trigger an infinite retry loop.

Common misconceptions

  • A DLQ fixes the failure — it isolates the message; the cause still needs diagnosis
  • Every failure should go to the DLQ — transient errors should retry with backoff, and only exhausted or permanent failures should be parked
  • Replaying a DLQ is always safe — consumers must be idempotent, and ordering may be lost

Anti-patterns

  • Retrying a malformed message forever and blocking the partition
  • Moving messages to a DLQ and never alerting or reviewing them
  • Replaying an entire DLQ without checking consumer compatibility and idempotency

Related concepts

Related examples

Authoritative source

https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/

One bad message should not stop the stream

A consumer processes messages in order. A malformed message fails, is retried, fails again, and blocks every message behind it. A DLQ moves the message aside after a defined number of attempts or a non-retryable error. The consumer continues, and an operator can inspect the parked message with its error context.

{
  "RedrivePolicy": {
    "deadLetterTargetArn": "arn:aws:sqs:region:account:orders-dlq",
    "maxReceiveCount": 5
  }
}

The example is an SQS redrive policy. RabbitMQ uses a dead-letter exchange; Kafka often uses a separate DLQ topic with the original topic, partition, offset, and error headers. The mechanism differs, but the policy is the same: bounded attempts, preserved context, and visibility.

Classify the failure

Not every failure belongs in a DLQ. A timeout or a temporarily unavailable dependency should retry with exponential backoff and jitter. A schema mismatch, an invalid payload, or an authorization failure is permanent until the producer or the data is fixed; retrying it wastes capacity. Some systems use separate retry and DLQ topics so transient failures get a delay while permanent failures are parked immediately.

Preserve the original message, the exception, the consumer version, and the attempt count. Without the context, a DLQ becomes a pile of opaque payloads. Alert on DLQ depth and age; a growing queue is an operational signal even if the main pipeline is healthy.

Replay deliberately

Replaying is a new production event. Consumers must be idempotent, because the original delivery may have partially succeeded. Ordering may be lost if the DLQ is replayed out of order; check whether the consumer relies on sequence. Replay into a staging consumer first when the schema or code has changed. Record who replayed what and when.

When to use it

Use a DLQ when a bounded retry policy can still leave messages unprocessable and blocking progress is unacceptable. The advantage is isolation and diagnosis; the drawback is another queue to monitor, secure, and clean up. Compared to infinite retries, a DLQ makes failure visible; compared to dropping messages, it preserves the opportunity to recover them.