Articles
NATS JetStream Interview Questions: Consumers, Acknowledgments, and Replay
Prepare for NATS JetStream interview questions with consumers, acknowledgments, redelivery recovery, poison-message handling, and safe replay.
A worker charges a customer, crashes before it acknowledges the message, and receives the same event again. If your JetStream interview answer is “increase the acknowledgment timeout,” you have addressed timing but not correctness. The more useful answer identifies what the consumer knows, what the business system knows, and how a duplicate attempt is handled.
These NATS JetStream interview questions focus on durable and ephemeral consumers, explicit acknowledgments, bounded in-flight work, and deliberate replay. For a related exercise, practice explaining message-queue delivery semantics before walking through the failure trace below.
Evidence boundary: NATS documentation defines the JetStream behavior described here. The sample notification service, numerical settings, and interview answer structures are illustrative engineering exercises, not reports of a particular employer's interview or a production default.
The short answer: separate three kinds of state
A stream stores messages under a retention policy. A consumer tracks delivery and acknowledgment progress for a chosen view of that stream. Your application records whether the intended business effect happened. These states are related, but none is a substitute for the others.
An acknowledgment tells JetStream that a consumer finished a delivery attempt according to the application's policy. It does not prove that a payment, notification, or database update happened exactly once. Conversely, the effect can happen while the acknowledgment is lost. That gap is why a strong answer pairs at-least-once processing with stable event identities, idempotent effects, and reconciliation.
Use this interview shorthand: stream retention decides what may still be available; consumer state decides what this consumer has seen or acknowledged; business state decides what actually happened. When an interviewer changes the failure point, locate it in those three records before selecting a recovery action.
Which consumer should several workers use?
A durable consumer preserves its progress across worker restarts. For a worker pool that divides one logical subscription, multiple workers can use the same durable pull consumer and share its cursor and pending-work limits. Creating a separate consumer for every worker changes the semantics: each consumer may receive its own copy of matching messages, which is useful for independent applications but wrong for a simple competing-worker pool.
An ephemeral consumer is appropriate when state need not survive, such as a short-lived inspection tool. It is a poor default for a billing or notification processor that must resume at a predictable position. NATS also has Core NATS queue groups; do not describe them as if they were JetStream durable consumers with identical persistence and replay behavior.
| Requirement | Consumer design | Consequence to explain |
|---|---|---|
| Three workers share one processing workload | One durable pull consumer, three clients | One logical progress record, shared in-flight capacity |
| Analytics and billing need independent processing | Separate consumers on the same stream | Each application has its own progress and failure policy |
| One-off inspection of recent events | Ephemeral or carefully scoped replay consumer | Avoid disturbing production progress |
Name the stream and subject filter separately. A subject filter narrows a consumer's view; it does not transform a shared consumer into multiple independent business subscriptions. If you propose one consumer per tenant or event type, account for the operational cost, authorization model, and how you will observe lag across that inventory.
What does an acknowledgment actually guarantee?
With explicit acknowledgment, a message is delivered and remains pending until the consumer acknowledges it or the applicable redelivery condition is reached. If the worker finishes but its acknowledgment never reaches the server, JetStream may deliver it again. That is normal at-least-once behavior, not evidence that the broker duplicated the business effect.
Distinguish a plain acknowledgment from a confirmed or double acknowledgment. The latter lets a client wait for server confirmation that its acknowledgment was processed, reducing ambiguity at that boundary. It still cannot atomically commit an external database transaction and the consumer's acknowledgment. The application must decide when to ack relative to its own durable effect.
A useful processing order is: validate the message and stable event ID; apply the business change idempotently in a durable store; commit the result; then acknowledge. A duplicate attempt finds the committed event ID and acknowledges without repeating the effect. A permanent invalid message needs a separate quarantine decision, not an infinite loop of “retry until it works.”
If a worker acknowledges before committing, a crash can lose work. If it commits before acknowledging, a crash can create a duplicate delivery. The second order is usually safer when the effect is idempotent and recoverable. State that trade-off explicitly rather than claiming exactly-once end-to-end delivery.
Walk through a crash after the side effect
Imagine stream sequence 4821 contains event ID evt-4821: “send a due-date notification to account A.” The pull consumer delivers it to worker W1. W1 inserts a notification-outbox row keyed by evt-4821 and commits the transaction. The process then dies before sending its acknowledgment.
After the consumer's redelivery condition, W2 receives the event. W2 must not send a second notification merely because the delivery is new. It queries the outbox or effect ledger by evt-4821. If the committed row exists, W2 resumes or verifies the downstream send using the same idempotency key. It then acknowledges when its durable responsibility is complete.
Now change the trace: W1 inserted the row but its database transaction rolled back. W2 finds no committed effect and performs the work. Change it again: the downstream notification provider accepted the send, but the callback was lost. The outbox should represent an uncertain state; blindly retrying without a provider idempotency key or reconciliation risks duplicate sends.
This is the central interview asset: ack uncertainty, transaction uncertainty, and external-effect uncertainty are distinct. Record which evidence you need for each. A consumer's delivery count alone cannot tell you whether an email was sent or a charge captured.
Ask for the event's stable identifier, transaction boundary, and downstream idempotency contract. If those are unavailable, explain the residual risk and the repair process. An honest bounded answer is stronger than a promise of exactly-once delivery that crosses systems without a shared transaction.
How do Ack Wait and MaxAckPending change the result?
Ack Wait controls when unacknowledged work becomes eligible for redelivery, subject to the consumer's configuration. Set it from observed handler duration and failure objectives, not by copying a number from another service. Too short, and healthy slow work may race with a second worker. Too long, and crashed work sits pending before recovery. If a task can legitimately run longer, consider progress signals or a different work decomposition rather than silently expanding the timeout forever.
MaxAckPending bounds unacknowledged deliveries for the consumer. In a worker pool, it is a shared capacity control, not a per-worker promise. If it is exhausted, adding workers alone may not increase delivered concurrency. If it is much larger than the work pool can safely process, you can accumulate too many in-flight tasks and make a failure storm harder to reason about.
For pull consumers, batch size and fetch expiration shape how clients request work. A fetch returning fewer messages than the maximum during a quiet period is not necessarily an error. Bound batch size by memory and processing time; avoid fetching more work than a client can finish before its acknowledgment policy becomes relevant.
Suppose three workers can each safely handle four notifications concurrently. A starting MaxAckPending of twelve is an illustrative capacity hypothesis, not a recommended default. Measure pending count, redelivery count, handler latency, downstream rate limits, and outbox backlog. If redelivery rises while CPU is idle but the provider is throttling, the fix is not simply a higher consumer limit.
Redelivery is not the same as replay
Automatic redelivery is a consumer retry of a delivery that remains unacknowledged under its policy. Deliberate replay is an operator or application decision to revisit stored messages or rebuild an outcome. Replay may use a new consumer, a different start position, or an application-level repair job. It is limited by what the stream still retains and by the selected consumer configuration.
The mistake is to say “we can replay everything” without checking retention and side effects. A stream with messages already removed under its retention policy cannot reconstruct them. A replay of retained events can still reapply business effects unless the handler and destination are idempotent for the replay's scope.
For an incident involving evt-4821 through evt-4860, define the cohort by stable event IDs and a recorded incident window. Freeze the intended result: one notification outcome per eligible event, excluding invalid or canceled accounts. Then choose whether ordinary redelivery will finish the work or whether a new scoped repair consumer is needed. Keep production and repair progress separate so a test run cannot accidentally advance the live consumer.
Before starting repair, sample the payload schema and current business state. A historical event interpreted under today's rules can produce a different answer. Version the handler or explicitly translate old payloads; record the chosen code and configuration. Replaying into a sandbox first can expose duplicate-risk paths before touching a real provider.
Afterward, reconcile three counts: eligible source events, unique durable effect IDs, and completed downstream outcomes. Add an exception list for quarantined or intentionally skipped events. “Consumer lag is zero” is not sufficient: a zero-lag consumer can have acknowledged messages whose business effect failed, and a repair consumer can reach the end while the destination still has pending work.
What do you do with a poison message?
A malformed payload or unsupported schema can fail every attempt. More retries do not make it valid. Classify the failure as transient or permanent using evidence from the handler and dependency. Transient examples include a short provider outage or database timeout; permanent examples include a payload missing a required identity or an unrecognized schema version that the current code cannot interpret.
Set a bounded attempt policy and record the reason, event ID, original stream sequence, payload version, and handler version in a quarantine store with appropriate access controls. Decide whether to acknowledge the original delivery only after the quarantine record is durable and the operational contract allows it. Otherwise the event can disappear from the work queue without a repair trail.
When the handler is fixed, replay the quarantined cohort deliberately. Preserve the original event identity so the effect ledger prevents duplicates. Track how many were retried, succeeded, remained invalid, or changed classification. Avoid using a broad “replay all” control just to fix a handful of known failures.
An interviewer may ask whether a negative acknowledgment solves poison messages. It can request redelivery, but it does not diagnose the cause or provide a safe terminal outcome. Explain the backoff, attempt ceiling, quarantine owner, alert threshold, and repair procedure. Those details show you understand operations, not just an API name.
Five interview questions worth rehearsing
| Question | JetStream angle to practice |
|---|---|
| Explain Kafka and Message-Queue Delivery Semantics | Explain why broker progress does not prove a unique business effect. |
| Design High-Throughput Messaging Infrastructure | Bound pending work while workers and downstream capacity change. |
| Implement an Idempotent Versioned Database Update | Guard a repeated event against duplicate or stale writes. |
| Design a Thread-Safe Bounded Blocking Queue | Reason about backpressure between fetched and processed work. |
| Design a Reliable Notification System | Connect retries and outbox state to a real user-visible outcome. |
In a mock answer, draw the three state owners first: stream, consumer, and business ledger. Run one failure at each boundary. Then choose a metric that would disprove your proposed repair. This structure gives the interviewer something concrete to challenge.
A concise answer to use in an interview
“I would give the worker pool one durable pull consumer if the workers share one workload. I would use explicit acknowledgments after an idempotent, durable business effect. If the worker crashes after committing but before the ack, JetStream can redeliver, so the next worker must recognize the event ID and avoid a second effect. I would bound in-flight work with MaxAckPending, tune the redelivery timing from actual processing latency, and quarantine permanent failures with a repair trail. For deliberate replay, I would check retention, isolate the repair consumer, preserve event identities, and reconcile source events against completed outcomes.”
The point is not to memorize that paragraph. Practice changing the crash point and proving the answer still holds. Start with Explain Kafka and Message-Queue Delivery Semantics, then adapt the trace to JetStream's documented consumer and acknowledgment behavior.
Sources and Further Reading
- NATS: Delivery and Acknowledgment
- NATS: Acknowledgment
- NATS: Pull Consumers
- NATS: Worker Pool
- NATS: Retention Policies
Research checked September 21, 2026. JetStream features and operational defaults can change; verify your deployed version and configuration.