Lesson 16 · Senior NATS practice

Poison messages, DLQ design, and safer JetStream failure handling

How to reason about redelivery, poison messages, no-DLQ reality, and what a cleaner failure-handling design would look like in this repo.

Your win: explain the repo’s current Ack-only failure model honestly, then describe what a safer poison-message and DLQ strategy would look like without pretending JetStream already gives it to us here.

Why this page matters more than it looks

Earlier lessons taught the mechanics honestly: success acks, retryable failure waits for redelivery, and poison or unparseable messages are ack-dropped. That is already better than hand-wavy reliability talk. But senior understanding goes one step further: it turns that mechanical description into design judgment.

Once you do that, new questions appear. What should happen when a message is permanently bad? When should the system retry in place? When should it preserve failure evidence somewhere safer? What is lost when a poison message is simply acknowledged away? Those are the questions this page is here to train.

In plain English Plain English: retrying forever is not resilience, and acking poison messages away is not free either.
The failure-handling rule A safe eventing design must preserve both liveness and evidence; it should not force the team to choose silently between stuck progress and invisible loss.

What a DLQ actually buys you

A DLQ is not just a storage bucket for bad messages. Its real job is to preserve the failed event, preserve the failure context, and still let the main flow keep moving. That is why the DLQ conversation is really a system-behavior conversation, not just a storage conversation.

The strongest senior answer here is honest: JetStream supports richer ack semantics than the repo uses today, and a future DLQ design could make failure handling more explicit, observable, and recoverable. The important thing is not to pretend that future design already exists in the current system.

Backend use case In this repo, the important gap is not only “no DLQ.” It is the combination of Ack-only handling, timeout-driven retry, and poison-message drop behavior that makes the trade-off worth discussing explicitly.
Common mistake Saying “just add a DLQ” without explaining how poison messages are classified, what metadata is preserved, and how normal flow keeps progressing safely.
Read this next

Ack semantics with a design lens

Revisit the JetStream model deep dive and compare its richer ack options with the repo’s simpler current policy.

JetStream model deep dive
Repo NATS map

Check yourself (from memory)

Q1. What is the most senior purpose of a DLQ in this context?

The goal is liveness plus evidence, not magical reliability.
Why is “ack poison and move on” an incomplete reliability story?
recall, then click to reveal
Because it restores liveness but may erase the evidence needed to investigate or recover the failed work. A safer design preserves both progress and diagnosability.
Want me to sketch a repo-specific JetStream DLQ design and message-shape for failed events? Ask me.

Sources. JetStream model deep dive; repo NATS map.