Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Queues  ›  Capstone Project

Dead Letter Queues — Where Failed Messages Go to Be Studied

Dead Letter Queues 12 minA dead letter queue receives messages that used up their retries, so failures are kept for inspection, alerting and replay instead of being silently discarded.

Dead Letter Queues — Where Failed Messages Go to Be Studied

One Hoplink link points at a page whose title contains broken characters. The "fetch-title" job crashes on it every time. Retrying cannot help: the message is simply bad. Without a plan, it is retried until the limit, then thrown away, and nobody learns why the preview is missing. A dead letter queue (DLQ) keeps it instead.

The rule

Retry what might pass; park what keeps failing; then look.

Every consumer has a retry budget, max_retries (3 by default). Once a message has failed that many times:

  • Without a DLQ, it is discarded. The failure disappears.
  • With a DLQ, it is moved to another queue you name, where it waits intact for you.
{
  "queues": {
    "consumers": [{
      "queue": "jobs",
      "max_retries": 5,
      "dead_letter_queue": "jobs-dlq"
    }]
  }
}

Create the second queue first with wrangler queues create jobs-dlq. A DLQ is an ordinary queue, so you choose what happens next:

  • Inspect. Look at the messages in the dashboard to see the body and understand the failure.
  • Alert. Attach a small consumer to jobs-dlq that records each failure in D1 and notifies the team.
  • Replay. After fixing the bug, send the parked messages back to jobs to run again.

Deciding when to give up belongs in the consumer too. Some errors are transient — a timeout, a 503, a 429 — and retrying later can succeed. Others are permanent — a malformed body, a link that no longer exists — and retrying only wastes the budget. For permanent errors, record the problem and ack() so the message stops cycling, or let it reach the DLQ where a person will see it.

The shortcut

For every error in a consumer, sort it with one question: "Could the exact same message succeed later?" Yes → retry() with backoff. No → handle it now (record and ack) or let it go to the DLQ. Every queue that does must-happen work gets a DLQ.

Tracing the broken-title jobStep 1 of 4
  1. First delivery

    The consumer throws while parsing the title. It is retried.

Trap: a DLQ that nobody watches. Messages pile up quietly, and the failure is as invisible as if they had been deleted.

Drills

Answer fast — trust the rule.

quick drill

A message fails more times than max_retries and the consumer has no DLQ. What happens?

quick drill

Which error is most likely permanent, so retrying will not help?

quick drill

What is a dead letter queue, technically?

quick drill

After fixing the bug behind 200 parked messages, what should you do?

quick drill

Which setup gives the team the best chance of noticing failures?

Remember

  • Retry what might pass; park what keeps failing; then look.
  • Shortcut: "could the same message succeed later?" Yes → retry with backoff; no → record, ack or DLQ.
  • Trap: a DLQ nobody watches is just a slower delete.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainA plan for failing jobs

Design how Hoplink's jobs queue handles failures: which errors to retry, which to stop retrying, what happens after max_retries, and how the team finds out and recovers.