FullStack Course LogoFullStack Course
Module: System Design
System Design·267·12 MIN READ

267: Idempotency, Deduplication, Delivery Semantics, and Exactly-Once Myths

TOPICS COVERED: Idempotency, Deduplication, Delivery Semantics, and Exactly-Once Myths

Learning outcomes

By the end of this lesson, you can:

  • explain and apply idempotent operations in a realistic implementation;
  • explain and apply idempotency keys in a realistic implementation;
  • explain and apply deduplication windows in a realistic implementation;
  • explain and apply at-most/at-least-once in a realistic implementation;
  • explain and apply exactly-once boundaries in a realistic implementation.

Prerequisites and retrieval

This lesson assumes the earlier 01–06 foundation and the preceding lessons in this module. Before you read, retrieve one concrete example from an earlier project where this same reliability concern appeared. Perhaps a request timed out after the server had already accepted it, or a message was delivered twice. The point is not to memorize a set of labels. The point is to make a defensible choice inside a large-scale distributed service, with its requirements, traffic, failure modes, cost, and operational constraints stated explicitly.

Terminology

  • Idempotent operations: Repeating the same operation produces no additional unintended effect. The operation may be received more than once, but the system's resulting state should be the same as if it had been received once.
  • Idempotency keys: A client- or server-generated operation key is stored with a request fingerprint and its result. If the request is retried, the service can return the earlier outcome instead of performing the effect again. The fingerprint also prevents one key from being reused for a different request.
  • Deduplication windows: An event consumer stores processed event IDs, or enforces uniqueness in the domain, for a defined period. The window must be long enough to cover the relevant retry and replay period.
  • At-most/at-least-once: At-most-once delivery may lose work, because the system can acknowledge or discard a message before the work is safely completed. At-least-once delivery may perform or deliver work more than once.
  • Exactly-once boundaries: Some platforms provide exactly-once processing inside a narrow transactional or log boundary. That guarantee does not automatically extend to an external payment provider, email service, database, or other side effect. End-to-end idempotency is still needed because the whole world is not one transaction.
  • Reconciliation: For critical money or inventory workflows, a periodic comparison detects missed, duplicate, or inconsistent states that retries alone cannot guarantee away.

Mental model

Treat Idempotency, Deduplication, Delivery Semantics, and Exactly-Once Myths as a design problem with observable inputs, outputs, invariants, and failure modes. A network can lose a response even though the server completed the work. From the client's perspective, that looks like a failed request, so the client may retry. Brokers and workers have similar uncertainty around acknowledgements. A safe system either makes duplicate execution harmless or gives the operation a durable identity that lets it detect the duplicate.

The implementation should make its assumptions visible. Define what must remain true, narrow uncertainty at each boundary, and leave enough evidence to demonstrate why the design is safe. That evidence might be tests, types, database constraints, metrics, logs, or a diagram of the transaction boundary.

A useful sequence for both interviews and production design is:

text
requirement -> constraints -> model -> implementation -> failure analysis -> verification

Do not jump from a requirement directly to a library call such as "enable exactly once" or "retry the request." First state the invariant. Then decide which mechanism enforces it, what it does not cover, and how you will observe a violation.

Deep dive

1. Idempotent operations

The problem appears when an operation is repeated: a client retries after a timeout, a user double-clicks, or a worker restarts after completing work but before acknowledging it. An idempotent operation produces no additional unintended effect when that repetition happens. GET- and PUT-like HTTP semantics can help because repeated reads or replacement writes have naturally bounded effects, but the HTTP verb alone does not make a business action safe. Charging a card, reserving inventory, or sending an email requires explicit idempotency design.

Decision rule: Use idempotent operations deliberately when they make the contract or invariant easier to prove. If an apparently idempotent interface merely reduces typing while hiding an assumption about identity, ordering, or concurrency, prefer a more explicit design.

2. Idempotency keys

An idempotency key gives one logical operation a durable identity. Persist the key together with a request fingerprint and the result that should be returned. A retry with the same key and the same request can then return the prior outcome rather than creating the effect again. This is especially useful when the original response was lost after the effect succeeded.

The fingerprint is not optional bookkeeping. A client must not be able to send a different amount, account, or order under an already-used key and receive an ambiguous result. The service should reject a fingerprint mismatch. The write that claims a new key must also be atomic or protected by a uniqueness constraint; otherwise two concurrent requests can both observe that the key is unused and both perform the effect.

Decision rule: Use idempotency keys deliberately when they make the contract or invariant easier to prove. If they only reduce typing while hiding an assumption, prefer the more explicit design.

3. Deduplication windows

An at-least-once consumer should expect the same event to arrive more than once. It can store processed event IDs and ignore an ID it has already handled, or it can rely on a domain uniqueness constraint such as one shipment record per order event. These approaches protect different boundaries, so state which one owns the invariant.

Deduplication storage is not free and usually cannot be kept forever. Its retention or window must cover the broker's retry and replay horizon relevant to the workflow. If an old event can be replayed after the record has expired, the consumer may treat it as new. For workflows where a time-bounded window is not enough, durable domain uniqueness and reconciliation may be safer than relying on an expiring event-ID cache.

Decision rule: Use deduplication windows deliberately when they make the contract or invariant easier to prove. If the window only hides an assumption about how long duplicates can arrive, make that horizon explicit and choose a stronger constraint when necessary.

4. At-most/at-least-once

At-most-once delivery chooses not to repeat work, but it can lose work. A message may be discarded or acknowledged before processing is durably complete. At-least-once delivery retries until the system believes the work was accepted, so it reduces loss at the cost of possible duplicates. Most reliable systems prefer at-least-once delivery plus idempotent consumers for external effects.

Neither label means that every part of a distributed workflow has one universal behavior. A broker may provide at-least-once delivery while the consumer's call to an external service remains uncertain. Describe each boundary separately: delivery, processing, persistence, acknowledgement, and external side effect.

Decision rule: Use at-most/at-least-once deliberately when it makes the contract or invariant easier to prove. If losing a message is unacceptable, do not choose at-most-once merely because duplicate handling is inconvenient; make the consumer safe to retry instead.

5. Exactly-once boundaries

"Exactly once" is usually a boundary-specific guarantee, not a promise about an entire business workflow. A platform may atomically read a log record, update its own state, and advance an offset. That can prevent duplicate processing inside that transaction. It cannot automatically make a separate payment provider, email system, or database participate in the same transaction.

The practical design is to identify the narrow boundary where exactly-once processing is available, then use idempotency or deduplication at every external boundary. Otherwise a worker can complete an external side effect and fail before recording or acknowledging it, causing a retry.

Decision rule: Use exactly-once boundaries deliberately when they make the contract or invariant easier to prove. If the design treats a local platform guarantee as end-to-end exactly once, the hidden gap is a failure mode, not a simplification.

6. Reconciliation

Retries, keys, and deduplication reduce uncertainty; they do not eliminate every failure. For critical money and inventory workflows, run a periodic reconciliation process that compares the system's records with the authoritative source or with the expected relationship between records. It can find missed, duplicate, or inconsistent states and route them for correction.

Reconciliation is a safety net, not permission to ignore idempotency. It detects problems after the fact, so the design still needs bounded retries, durable identity, useful audit data, and an operational path for resolving discrepancies.

Decision rule: Use reconciliation deliberately when it makes the contract or invariant easier to prove. If it is the only protection for a critical side effect, the primary workflow is carrying too much uncertainty.

Worked example

Consider a large-scale distributed service whose requirements, traffic, failure modes, cost, and operational constraints must be explicit. Start by writing the requirement in one sentence. Then list the input and output contracts and identify which concept above owns each failure mode. For a payment endpoint, for example, the contract must say what happens when the client retries with the same key, when it reuses that key with different input, and when the dependency times out after accepting the charge.

The important design move is separation of concerns. Parsing and validation belong at the boundary. Domain rules belong in the domain or service layer. Persistence rules belong in the database or repository. Presentation rules belong in the client. Mixing these concerns can make a happy-path demo look shorter, but it makes duplicates, partial failure, and edge cases much harder to reason about.

text
Client
  |
DNS -> CDN / Edge
  |
Load Balancer -> API instances -> Cache
                          |          |
                          +------> Primary datastore
                          |
                          +------> Queue / Stream -> Workers

Walk the design through at least four cases:

  1. The normal path, where the request or event is processed once.
  2. An empty or missing value, such as an absent idempotency key or event ID.
  3. A duplicate, retry, or concurrent path, where relevant. Include the case where two requests claim the same identity at the same time.
  4. A dependency failure, including a timeout after the dependency may have completed the side effect.

For every case, state which layer detects the problem and what the caller observes. Does the API return the stored prior response? Does it reject a fingerprint mismatch? Does the worker retry, acknowledge, or send the event for investigation? This level of explanation is what a senior code review or technical interview expects: not just the happy path, but the invariant and the observable behavior when the system is uncertain.

Production perspective

Production correctness is broader than "the code works on my machine." Ask how the design behaves during deploys, retries, partial failure, stale clients, concurrent requests, malformed data, schema changes, and high-cardinality traffic. Prefer explicit contracts, bounded resource usage, structured errors, and measurable behavior. Optimize only after evidence identifies a bottleneck or a risk.

When the topic involves an external dependency, define a timeout and cancellation strategy. A timeout limits waiting; it does not prove that the dependency did not complete the operation. When the topic involves persistence, define transaction and consistency expectations, including when an idempotency record and its business effect become visible. When it involves user-visible state, define loading, empty, error, stale, and success states. When it involves security, assume the client can be modified and all network input is untrusted.

Guided lab

Design an idempotent payment-creation endpoint and an at-least-once order-event consumer. Define key storage, the response for a duplicate, the behavior for a fingerprint mismatch, retention, and a reconciliation job. Your design should make clear where uniqueness is enforced and which failures can still leave work uncertain.

Complete the lab with this discipline:

  1. Write the requirement and two non-requirements.
  2. List input, output, and error contracts before implementation.
  3. Implement the smallest correct vertical slice.
  4. Add at least one invalid-input test and one edge-case test.
  5. Instrument or inspect the behavior instead of guessing.
  6. Refactor one hidden assumption into an explicit type, constraint, function, or configuration.
  7. Explain one alternative design and why you did not choose it.
  8. Record a short "what would break at 10x scale?" note.

Edge cases and failure modes

  • Idempotent operations: Test absence, malformed input, duplicates, ordering and concurrency where applicable, and behavior at the smallest and largest credible sizes.
  • Idempotency keys: Test an absent key, malformed key or fingerprint, a repeated request, a fingerprint mismatch, concurrent claims for the same key, and behavior at the smallest and largest credible sizes.
  • Deduplication windows: Test absence, malformed input, duplicates, ordering and concurrency where applicable, an event replayed after retention expires, and behavior at the smallest and largest credible sizes.
  • At-most/at-least-once: Test absence, malformed input, duplicates, ordering and concurrency where applicable, acknowledgement around a worker crash, and behavior at the smallest and largest credible sizes.
  • Exactly-once boundaries: Test absence, malformed input, duplicates, ordering and concurrency where applicable, and an external side effect completed before the local transaction or acknowledgement failed. Check behavior at the smallest and largest credible sizes.

Common mistakes and debugging

  • Solving the example instead of the requirement: a copied pattern can be syntactically correct but architecturally wrong.
  • Hiding uncertainty with assertions, broad exception handlers, permissive schemas, or "temporary" any values.
  • Testing only the happy path and discovering the real contracts only after integration.
  • Optimizing before measuring, or selecting a scalable mechanism without a scale requirement.
  • Letting client-side behavior stand in for server-side authorization, validation, or persistence guarantees.

For debugging, reproduce the smallest failing case first. Inspect the actual request key, fingerprint, event ID, acknowledgement, stored result, and execution trace rather than inferring them from the caller's view. Trace the boundary where the invariant first becomes false: source or build, browser or DOM, Network or HTTP, server or route, database or query, or deployment or configuration. Then fix the layer that owns the invariant instead of adding a downstream patch that only hides the symptom.

Interview questions

  1. What problem do idempotent operations solve, and what trade-off or failure mode would make you choose a different approach?
  2. What problem do idempotency keys solve, and what trade-off or failure mode would make you choose a different approach?
  3. What problem do deduplication windows solve, and what trade-off or failure mode would make you choose a different approach?
  4. What problem does at-most/at-least-once solve, and what trade-off or failure mode would make you choose a different approach?
  5. What problem do exactly-once boundaries solve, and what trade-off or failure mode would make you choose a different approach?

Checkpoint

Without notes, explain Idempotency, Deduplication, Delivery Semantics, and Exactly-Once Myths to another developer in five minutes. Your explanation must include one invariant, one edge case, one production failure mode, and one alternative design. Then implement a small example without copying the lesson code. Be prepared to explain which boundary your example protects and which failures remain outside that guarantee.

Mastery checklist

  • I can define the core terms precisely.
  • I can choose a design from requirements instead of from habit.
  • I can implement and test the normal path and edge cases.
  • I can explain the runtime, storage, or complexity cost.
  • I can identify which layer owns validation, errors, and recovery.
  • I can compare at least two reasonable alternatives.
  • I can explain how the design changes at larger scale or stricter reliability.

References

Reader page: /system-design/lesson/267/idempotency-deduplication-delivery-semantics-and-exactly-once-myths