awesome-everything RU
↑ Back to the climb

Queues, Streams, Eventing

At-most-once, at-least-once, exactly-once: the three delivery contracts

Crux What the three delivery guarantees mean, why exactly-once delivery is impossible, and why at-least-once is the production default.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at junior altitude — the surface
◷ 8 min

A payment worker processes a “charge $50” message and crashes before telling the queue it is done. The queue redelivers. The customer is charged twice. This is not a bug in your code — it is the default behaviour of every production queue in the world.

The three contracts

Every message queue offers a delivery contract — a guarantee about how many times a message reaches a consumer when failures happen.

At-most-once. The broker sends the message once and never retries. If the network drops the message, it is gone. No duplicates, but possible loss. Use case: debug logs, non-critical telemetry. Never use for money, orders, or any event where loss has business consequences.

At-least-once. The broker retries until the consumer sends an explicit acknowledgement (ack). If the ack is lost, the broker redelivers. The message arrives at least one time, but possibly more. At-least-once is the default in SQS, RabbitMQ (with ack), and Kafka with default settings.

Exactly-once. Every message is processed exactly one time regardless of retries. This is what you want. The problem: pure exactly-once delivery over an unreliable network is mathematically impossible — the Two Generals’ Problem proves that two parties over an unreliable channel can never be certain they both agree on the same fact. You cannot guarantee both sides know a message was delivered exactly once.

What you can achieve is exactly-once processing — the consumer’s side effect (charge a card, send an email, update a row) happens exactly once, even if the broker delivers the message more than once. The trick is an idempotent consumer.

Three delivery contracts at a glance
at-most-onceSend once, no retry. Can lose messages. Best for metrics, logs.
at-least-onceRetry until ack. Can deliver 2+ times. Production default. Requires idempotent consumer.
exactly-onceDelivery impossible. Processing achievable via consumer dedup. 20–30% throughput cost in Kafka.

Why at-least-once is the safe default

At-most-once accepts loss. For a payment system, a lost “charge customer” message means a missed transaction — unacceptable. At-least-once accepts duplicates. A duplicate “charge customer” message means charging twice — also bad, but fixable on the consumer side. Exactly-once delivery is not achievable without adding expensive coordination.

The industry convergence: use at-least-once delivery + make the consumer idempotent. The consumer checks “have I already processed this message ID?” before acting. Duplicates are ignored. The queue can retry freely without causing harm.

Quiz

Which delivery guarantee is the default for SQS and Kafka?

Quiz

Why is exactly-once processing achievable while exactly-once delivery is not?

Order the steps

Order the steps of an at-least-once payment flow with consumer-side dedup:

  1. 1 Producer generates a unique message ID and sends 'charge $50' to the broker
  2. 2 Broker stores the message durably and acks the producer
  3. 3 Consumer receives the message and reads the ID 'msg-7a3f'
  4. 4 Consumer checks the dedup store: 'have I processed msg-7a3f before?'
  5. 5 Dedup store says 'no' — consumer calls the payment API and records the charge
  6. 6 Consumer writes 'msg-7a3f processed' to the dedup store
  7. 7 Consumer acks the broker — message removed from the queue
Recall before you leave
  1. 01
    Name the three delivery guarantees and one use case each.
  2. 02
    Why is at-least-once the production default instead of exactly-once?
  3. 03
    What property must a consumer have to make at-least-once delivery safe?
Recap

Every queue offers a delivery contract: at-most-once accepts loss, at-least-once accepts duplicates, exactly-once delivery is impossible because the Two Generals’ Problem proves no finite protocol over an unreliable channel can give both parties certainty of agreement. Exactly-once processing is achievable: the consumer maintains a dedup log keyed by message ID and skips any message it has already handled. This converts at-least-once delivery into exactly-once processing at the cost of a dedup store, which is why at-least-once is the production default in SQS, Kafka, and RabbitMQ.

Connected lessons
appears again in202
Continue the climb ↑The three failure legs — where duplicates and losses actually happen
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.