At-Least-Once Delivery
The default network semantics of any realistic EDI deployment — and the raison d'être of receiver-side idempotency.
Problem
No distributed system can, without specific coordination, guarantee exactly-once delivery in the presence of network failures. When the sender has not received the MDN, it cannot tell "the message was delivered and the ACK was lost" apart from "the message was not delivered". If it favours completeness, it retransmits — producing duplicates.
Forces
- The network is unreliable. Routers, MTU, firewalls, TLS timeouts, NAT: plenty of reasons for an ACK to be lost independently of the payload.
- The sender must lean toward completeness. A lost order is more expensive than a deduplicated one.
- The receiver can deduplicate. It is the only party with a consistent view of what it has already accepted.
- Pure exactly-once does not exist at the transport level — it is obtained only by composing network at-least-once + receiver-side deduplication.
Solution
Explicitly accept that the transport stack is at-least-once, document the contract in the partner agreement, and invest in receiver-side deduplication (Idempotent Receiver) rather than chasing an illusory exactly-once. The sender applies retries with exponential backoff and jitter; the receiver maintains an idempotency-key table over a window.
sender ──────► partner
│ │
│ MDN/Receipt │
◄────────────────┘ ── lost ✗
→ sender cannot tell "delivered, ack lost"
apart from "not delivered".
→ it retries. Partner gets 1 or N copies.
→ partner must dedupe (Idempotent Receiver).
EDI implementation
AS2 is natively at-least-once: the MDN is just an application-level
acknowledgement. AS4 is the same, with eb:Receipt that
may be lost. Kafka with acks=all + enable.idempotence=true on the producer side delivers
at-least-once reinforced by broker-side deduplication over 5 minutes.
RabbitMQ with manual acknowledgements reproduces the same semantics.
All modern EDI middlewares (Sterling B2B, Mulesoft, BizTalk) advertise
their SLA as at-least-once and require deduplication at the hub.
Anti-patterns
- Promising exactly-once to the business. The business will conclude a bug as soon as the first duplicate arrives. Document at-least-once + deduplication explicitly.
- Disabling retries to avoid duplicates. Less frequent mistake, more expensive: visible duplicates traded for silent losses.
- Sender-side deduplication only. The sender does not know what the receiver has accepted. Dedup must live where the final state is observable.
- Ack before processing. If the receiver acknowledges before persisting, a crash loses the message. The ack must follow the application commit (Outbox-style).
Related patterns
- At-Most-Once — the inverse counterpart, semantics for non-critical logs/telemetry.
- Idempotency — the pattern that makes at-least-once acceptable for the business.
- Guaranteed Delivery — the broker-level guarantee layered on top.
Sources
- Kleppmann M. — Designing Data-Intensive Applications, O'Reilly 2017, chap. 11 "Stream Processing" (semantics: at-most-once, at-least-once, exactly-once). dataintensive.net
- Apache Kafka — Delivery semantics. kafka.apache.org/documentation/#semantics
- RFC 4130 — MIME-based Secure Peer-to-Peer Business Data Interchange Using HTTP, Applicability Statement 2 (AS2). §7.3 describes the unreliable MDN acknowledgement. rfc-editor.org/rfc/rfc4130