At-least-once delivery means a sender keeps retrying until it receives evidence that a message was accepted. The receiver may handle the same message more than once, so consumers need idempotency, deduplication, or both.
It is the usual guarantee behind durable queues, webhook retries, and outbox relays. It is practical because it favors delivery over uniqueness. Losing a message is usually worse than receiving a duplicate.
How it works
The sender stores or can recreate the message, sends it to a broker or receiver, and waits for an acknowledgment. If the acknowledgment is missing, times out, or is lost on the network, the sender retries.
sequenceDiagram participant Producer participant Broker participant Consumer Producer->>Broker: Publish event Broker->>Consumer: Deliver event Consumer--xBroker: Ack is lost or delayed Broker->>Consumer: Redeliver same event Consumer->>Broker: Ack accepted
The duplicate is not always caused by a bug. It can be the correct response to ambiguous state. If a consumer completed the business work but crashed before acknowledging, the broker cannot know whether the work happened. Redelivery is the conservative choice.
Delivery guarantees
Messaging systems usually talk about three guarantees.
| Guarantee | Meaning | Practical consequence |
|---|---|---|
| At-most-once | A message is delivered zero or one time | No duplicates, but loss is possible |
| At-least-once | A message is delivered one or more times | No loss after durable publish, but duplicates are possible |
| Exactly-once | A message has one observable effect | Usually requires idempotent processing plus transactional state |
“Exactly once” is often a property of a narrow subsystem, not a whole business flow. Once a workflow crosses databases, APIs, queues, and humans, the design still needs duplicate tolerant behavior.
Consumer design
The consumer owns most of the safety work.
- Use a stable message ID or idempotency key.
- Store processed IDs with a uniqueness constraint when duplicate effects matter.
- Make state transitions conditional. For example, move an order from
pendingtopaid, not from any state topaid. - Commit dedupe state and business state together when possible. The inbox pattern does this with a local transaction.
- Treat retries as normal traffic. Logs and alerts should distinguish transient retries from permanently failing messages.
Failure modes
At-least-once delivery does not guarantee ordering, freshness, or successful processing. A message can arrive twice, arrive after a newer event, or fail forever because the payload is invalid. For permanent failures, route the message to a dead-letter queue and alert the owning team.
When to use it
Use at-least-once delivery when business correctness requires eventual delivery and the consumer can tolerate duplicates. It fits payments, order updates, webhook events, audit records, and cross-service workflows where a missed event would create lasting inconsistency.
Prefer at-most-once only for disposable signals such as typing indicators, presence pings, or metrics where loss is cheaper than deduplication.
