Delivery Semantics
Updated June 6, 2026Imagine you're building an event-driven system where a billing service needs to process payments whenever a user clicks "Checkout." You drop the "Process Payment" event into a message broker like Kafka or RabbitMQ, and the billing service picks it up.
But networks are flaky. Servers crash. What happens if the message gets lost in transit? What if the billing service crashes right after receiving the message but before charging the credit card? Or worse, what if it charges the card but crashes before telling the broker, and the broker sends the message again, double-charging the user?
This is what delivery semantics covers — the guarantees a messaging system provides about how many times a message will be delivered.
There are three types:
- At-most-once
- At-least-once
- Exactly-once
At-Most-Once (Fire and Forget)
With at-most-once delivery, a message is delivered zero or one time. The system tries to deliver it, but if something goes wrong, it drops the message and moves on.
Think of a paperboy throwing newspapers from a bicycle. If the paper lands in a puddle, he doesn't go back. You get the paper at most once.
How it works: The producer sends the message and doesn't wait for an acknowledgment. The consumer receives the message, and the broker deletes it from the queue before the consumer even finishes processing.
When to use it: Use this when data loss is acceptable, but high throughput and low latency are critical.
- IoT sensor data: If a temperature sensor sends a reading every second, missing one reading doesn't matter. The next one arrives in a second.
- Video streaming metrics: Sending a ping every 10 seconds to calculate rough viewer counts. A missed ping is irrelevant.
For which use case would at-most-once delivery be the right choice?
At-Least-Once (Guaranteed Delivery)
With at-least-once delivery, the system guarantees the message will be delivered and processed, but in failure scenarios it might be delivered more than once.
Think of certified mail. The postman hands you a package, but won't leave until you sign. If you take the package but refuse to sign, he comes back tomorrow and hands you another copy until he gets the signature.
How it works: The broker sends the message to the consumer but keeps a copy. The consumer processes the message and then sends an ACK back to the broker. Only then does the broker delete the message. If the consumer crashes before sending the ACK, or if the ACK is lost in transit, the broker redelivers to another consumer.
At-least-once — broker keeps message until ACK, redelivers on crash
Why does at-least-once delivery require consumers to be idempotent?
When to use it: This is the default for most systems (SQS, RabbitMQ). Use it when you cannot lose data, but your consumer must be idempotent — processing the same message twice must have the same effect as processing it once.
- Ride status updates: If the app receives "driver has arrived" twice, it just shows "arrived" both times. No harm done.
- Database updates: If the message says
UPDATE users SET status = 'active' WHERE id = 5, running it twice is harmless.
Exactly-Once (The Hardest Problem)
With exactly-once delivery, the message is guaranteed to be delivered and processed exactly one time. No data is lost, no duplicates are processed.
Exactly-once is hard to achieve because it requires coordination between the producer, the broker, and the consumer. It's theoretically impossible to guarantee over an unreliable network (the Two Generals' Problem), but systems approximate it using at-least-once delivery plus transactional deduplication.
Kafka achieves "exactly-once semantics" (EOS) by assigning sequential IDs to messages and using transactional commits. If a producer retries sending a message, Kafka sees the duplicate ID and drops it. On the consumer side, the offset (tracking what was read) and the output are updated in a single atomic transaction.
Exactly-once — dedup table prevents duplicate processing, check-and-act is atomic
A payment processing consumer receives the same "charge $50" event twice due to a retry. What delivery semantic would prevent this from double-charging the user?
When to use it: Use this when operations are strictly non-idempotent and absolutely cannot happen twice, and you are willing to pay a performance cost for coordination.
- Financial transactions: You cannot process a "$100 withdrawal" event twice.
- Analytics billing: Charging an advertiser per ad click. A duplicate message means double-billing.
Comparing the Three
| At-Most-Once | At-Least-Once | Exactly-Once | |
|---|---|---|---|
| Guarantees | May be lost | Always delivered (possibly twice) | Delivered exactly once |
| Data loss | Possible | No | No |
| Duplicates | No | Possible | No |
| Performance | Fastest | Fast | Slowest |
| Complexity | Lowest | Medium | Highest |
| Use case | Metrics, IoT | Most business events | Financial, billing |
Summary
When designing event-driven systems, you must explicitly choose delivery semantics based on business needs. At-most-once is fast but drops data. At-least-once is the industry standard but requires idempotent consumers. Exactly-once is complex and slow, but necessary for strict financial or transactional workloads where duplicates are catastrophic. In practice, most systems use at-least-once delivery and invest in idempotency rather than paying the overhead of exactly-once coordination.
How helpful was this content?
Comments
Sign in to join the discussion
Saved on this device only
Sign in to sync progress across devices