← Back to Database and Storage

Message Delivery Semantics

Delivery semantics across loss, duplication, retries, and processing guarantees.

Database and StorageDelivery SemanticsMessage Queues

Delivery semantics describe what a messaging system promises when producers send messages and consumers process them. The three classic labels are at-most once, at-least once, and exactly once. They sound simple, but each one hides a different tradeoff between data loss, duplication, latency, and system complexity.

At-most once means the system will try to deliver a message, but it will not retry in a way that risks duplicates. If a message is lost in transit, acknowledged too early, or discarded after a crash, it is gone. This is acceptable only when occasional loss is cheaper than duplication. Metrics, low-value telemetry, and some ephemeral notifications fit this model because the system remains useful even if a few events disappear.

At-least once makes the opposite tradeoff. The system retries until it is confident the message was persisted or processed, so loss is unlikely, but duplicates are possible. Duplicates usually happen when the consumer completes the work but crashes before acknowledging, or when acknowledgements are delayed and the broker redelivers. This is the most common practical model because it is robust and easier to implement than true exactly-once delivery.

The real work with at-least once is moved to consumers. Handlers should be idempotent, meaning repeating the same message does not produce a second real-world effect. That can be done with unique business keys, deduplication tables, compare-and-set writes, or natural idempotency in the target operation. Without one of those patterns, retries turn into double charges, duplicate emails, or repeated inventory reservations.

Exactly once is the most attractive promise and the most misunderstood. In ordinary conversation it means no loss and no duplicates. In distributed systems it usually means something narrower, such as exactly-once processing within one broker and one transactional sink under strict conditions. As soon as a workflow spans external APIs, email gateways, or non-transactional systems, the guarantee gets much harder.

To approximate exactly once, systems combine transactional writes, idempotent producers, deduplicating consumers, and careful offset management. Patterns such as the transactional outbox and inbox help because they tie message publication or consumption to durable state changes. Even then, the guarantee often applies to system state, not to every external side effect.

Choosing a semantic is really choosing what failure you prefer to manage. If you cannot tolerate duplicates, you may pay higher latency and complexity to coordinate acknowledgements tightly. If you cannot tolerate loss, you must accept retries, deduplication, and occasionally repeated work. If neither loss nor duplication is acceptable because the domain is financial or regulatory, you usually end up combining at-least-once transport with strong idempotency and reconciliation.

The best design question is not Which semantic is best in theory? It is Which failure is survivable in this workflow? Once you answer that, the right acknowledgement, retry, and idempotency strategy becomes much clearer. Messaging systems are honest only when their delivery promise matches the consumer design built around it.