Glossary
Exactly-Once Delivery
Every message arrives once: never lost, never doubled. Networks cannot promise that on their own, so real systems get there by retrying until acknowledged and discarding anything they have already seen.
General definition
Exactly-Once Delivery is one of three delivery semantics a messaging system can offer. At-most-once sends and forgets: fast, but a message lost on the wire is gone. At-least-once keeps resending until the receiver acknowledges, so nothing is lost, but a message whose acknowledgement was lost will be sent again and may arrive twice. Exactly-once is what everyone wants: each message takes effect precisely once. The difficulty is that a sender who hears nothing back cannot tell whether the message was lost or only the acknowledgement was, so the network alone cannot provide it.
Real systems therefore build exactly-once as at-least-once plus deduplication. The sender attaches a unique identifier to every message and retries until acknowledged; the receiver records the identifiers it has processed and ignores repeats. Processing must be idempotent, meaning that applying the same message twice has the same effect as applying it once. That is also how stream platforms describe their exactly-once modes: an idempotent producer plus transactional writes, not a magic wire guarantee. The same pattern appears in a message queue with consumer acknowledgements and a deduplication store.
In chat the pieces have names in the XMPP standards:
- Stream Management (XEP-0198) counts stanzas in both directions, lets each side acknowledge what it has received, and allows a dropped connection to be resumed with unacknowledged stanzas resent rather than lost
- Unique and Stable Stanza IDs (XEP-0359) give each message an origin ID set by the sender and a stanza ID stamped by the server or room, so clients and archives can detect duplicates and refer to messages reliably
- Client-side deduplication keyed on those IDs, so a message resent after a reconnect appears once in the timeline
- Server-side archive as the source of truth, so a client that missed something fetches it by ID rather than trusting the live stream
Delivery to the server and delivery to the recipient are different events, which is why chat apps show a ladder of states: sent, delivered, read. A delivery receipt is the acknowledgement at the recipient end of that chain. Over a WebSocket, TCP guarantees ordered bytes on one connection, but it says nothing about what happens when the connection drops and a new one opens, which is exactly when duplicates and gaps appear.
In the Ethora ecosystem
Ethora runs on ejabberd, which implements XMPP stream management (XEP-0198) and stable stanza IDs (XEP-0359), so the acknowledgement, resumption and identification building blocks are part of the server rather than something each client reinvents. Every message is stored in the server-side archive on arrival, and the SDKs sync from that archive after a reconnect, which makes the archive the arbiter of what was delivered and in what order. Server-side unread counts and last-message data come from the same store, so they stay consistent with what the client shows.
For your own systems the same discipline applies at the edges: treat webhooks and integration events from Ethora as at-least-once and make your handlers idempotent on the message ID, and give messages you inject through the API your own identifier so a retried request does not create a duplicate. The Chat SDK handles the client-side reconciliation for you.