THN Interview Prep

Idempotency & at-least-once processing

Core details

At-least-once delivery: duplicates happen—handlers must converge.

Idempotency key pattern: deterministic business key + store outcome; replays short-circuit identical effects.

Transactional outbox: write business row + outbox event in one DB transaction → relay publishes reliably without “dual write” fantasy.

Inbox / dedupe table on consumer side for broker redeliveries.

Sagas / process managers: multi-step workflows with explicit compensations—not “distributed transactions” denial realism honest.

Problem this solves: retries, broker redeliveries, client double-clicks, and worker crashes create duplicate attempts. Business effects still need to converge to one intended result.

Simple mental model: delivery may happen many times; the externally visible effect should happen once.

Understanding

Retries—including client, gateway, and broker—multiply attempts. Without idempotent effects you get double charges, duplicate tickets, fan-out storms. “Exactly-once” rhetoric in interviews should be reframed honestly: effective-once via dedupe + deterministic side-effect design.

Ordering: single partition per entity often trades throughput for simpler reasoning—state when you’d relax ordering.

The visual model below shows the practical “effective-once” path: the producer records business state and an outbox row atomically, the relay publishes at least once, and the consumer uses an inbox/dedupe record so retries converge instead of duplicating side effects.

Idempotency and at-least-once processing path showing producer transaction, outbox relay, broker retries, consumer inbox dedupe, duplicate acknowledgement, and poison-message handling.

Senior understanding

Webhook story: verify signature before acknowledging; persist idempotency outcome before returning 2xx; classify transient vs permanent downstream errors to avoid infinite poison replays without DLQ observability.

Discuss clock skew minimally only if relevant—focus on key design + transactional boundaries first.

Minimal schema shape

TableKey fieldsPurpose
idempotency_keyskey, request_hash, status, response_ref, expires_atreject conflicting replays; return stored outcome
outbox_eventsevent_id, aggregate_id, type, payload, published_atreliable publish after business commit
consumer_inboxconsumer, event_id, processed_atdedupe broker redelivery per consumer

Store the idempotency record and the business effect in the same transactional boundary when possible. If they are split, the design needs a recovery story for “effect happened but outcome record was not saved.”

Common mistakes

  • Treating HTTP retry middleware as harmless without idempotency keys.
  • Returning 2xx to a webhook before the durable dedupe/effect boundary.
  • Using random request IDs when a deterministic business key is required.
  • Keeping dedupe rows forever without TTL, archival, or partitioning.
  • Calling broker “exactly once” and forgetting the external side effect.

Interview answer structure

“I assume at-least-once delivery and make the handler converge. The producer writes business state and an outbox row in one transaction. The relay may publish more than once. The consumer checks an inbox/dedupe table before applying the effect. For webhooks, I verify the signature first, persist the idempotency outcome before acknowledging, and route poison messages to a DLQ with alerting.”

Follow-ups to expect:

  • What key would you use for payment capture versus email sending?
  • How do you handle same key with different payload?
  • What happens if the worker crashes after the external API call?
  • How long do dedupe records live?

Diagram

Loading diagram…

See also

Mark this page when you finish learning it.

Spotted something unclear or wrong on this page?

On this page