03. WhatsApp / Messenger — Interview Q&A¶
~15 min read · Part 4 of 4 (Overview → HLD → LLD → Q&A)
Q1. Alice messages Bob while he's offline. Trace the guarantees.
The server dedups by client_msg_id, assigns a per-conversation seq, persists the message, and only then acks Alice (status sent). Bob has no live session, so it's enqueued in his durable inbox. On reconnect, Bob sends his last-seen seq and the server streams everything after it in order; Bob's client stores it and returns a delivery receipt that routes back to Alice. Nothing is lost (persist-first), nothing is duplicated (client dedup by server_msg_id), and order holds (per-conversation seq).
Common wrong answer to avoid: "Hold the message in memory until Bob comes online." Memory isn't durable; a server restart loses it. Persist first.
Q2. Can you guarantee exactly-once delivery?
Not on the wire — you get at-least-once delivery plus client-side dedup, which presents as exactly-once to the user. Each message has a client_msg_id (server dedup via a unique index) and a server_msg_id (client dedup on render). A lost ack triggers a retransmit that dedups; a redelivery isn't shown twice.
Common wrong answer to avoid: "Yes, exactly-once with two-phase commit." Over a lossy mobile link you cannot achieve true exactly-once transport; the practical answer is at-least-once + idempotent dedup.
Q3. How do you hold 500M concurrent connections?
A horizontally-scaled gateway fleet — each node holds ~100k persistent (WebSocket/MQTT) connections, so ~5,000 nodes at peak — plus a session registry mapping user_id → gateway node so any message routes to the node holding the recipient's socket. Connection state is soft; on node loss clients reconnect and re-register.
Common wrong answer to avoid: "A big load balancer to one server cluster with HTTP requests." Chat needs server-initiated push over long-lived connections, not request/response; and no single node holds that many sockets.
Q4. How is message order guaranteed within a conversation?
The server assigns a monotonic seq per conversation (the conversation is pinned to one shard, so it's a simple atomic counter), and the client renders by seq, not arrival order. If the client sees a gap (missing seq), it requests that message before rendering later ones.
Common wrong answer to avoid: "Order by timestamp." Clocks skew across senders and servers; a per-conversation sequence is the only reliable order.
Q5. Why persist before acking, not after delivering?
Because delivery is best-effort over an unreliable channel, but the ack must mean "durably stored." Persist-first means a delivery failure or recipient-gateway crash never loses the message (it's in the store/inbox and redelivers), and the sender's sent status is truthful.
Common wrong answer to avoid: "Ack once the recipient confirms." Then the sender is blocked on the recipient's connectivity, and offline recipients would make every send hang.
Q6. How do delivery and read receipts work? Receipts are just messages in the reverse direction. When Bob's client stores a message it emits a delivery receipt; when Bob opens the chat it emits a read receipt. Each routes back to the sender via the session registry (or queues if the sender is offline). Per-recipient receipt state is tracked separately from the message body. Common wrong answer to avoid: "The server marks delivered when it sends the push." Delivered must mean the recipient's device stored it, not that the server attempted a push.
Q7. How do group messages differ from 1:1?
A group message is 1:N fan-out of the same mechanism: expand to each member's session-or-inbox, applying dedup and per-conversation ordering. All members read the shared conversation seq, so everyone sees the same order; delivered/read is tracked per member. The member cap (256) bounds worst-case fan-out per message.
Common wrong answer to avoid: "Broadcast to a topic and forget." You lose per-member offline delivery, ordering guarantees, and receipts.
Q8. What happens on a lost ack — won't the user get duplicates?
No. Alice's client retransmits with the same client_msg_id; the server's unique (conv_id, client_msg_id) index rejects the duplicate insert and re-acks idempotently. Bob dedups any redelivery by server_msg_id. The retransmit is safe by construction.
Common wrong answer to avoid: "Duplicates are unavoidable with retries." They're avoidable precisely because of the dedup ids on both ends.
Q9. If end-to-end encrypted, how does the server order and deliver messages it can't read?
The server stores and forwards ciphertext and operates entirely on metadata: conv_id, seq, client_msg_id, server_msg_id, sender, timestamps. Ordering, dedup, offline queuing, and receipts all use that metadata, never the plaintext body. Key exchange happens client-to-client, out of the server's view.
Common wrong answer to avoid: "The server needs to decrypt to route." Routing and ordering need only metadata; decryption would break the E2E guarantee.
Deeper follow-ups¶
- How would you support multi-device sync so all of a user's devices stay consistent?
- How would you wake an offline app to drain its inbox (push notifications)?
- How would you handle a user in a 100k-member broadcast channel (beyond the 256 cap)?
- How would you implement "typing…" indicators without flooding the system?
- How would you geo-route connections so users connect to a nearby gateway?
- How would you bound and expire inbox growth for a device that never comes back?
How this round is scored¶
The chat round tests distributed-systems fundamentals under a concrete guarantee. The senior signal is stating plainly that exactly-once-on-the-wire is impossible and building at-least-once + dedup with the right ids, plus persist-before-ack so no message is ever lost. Getting ordering right (per-conversation sequence, not timestamps, with client gap-detection) and the connection/session-registry architecture for hundreds of millions of sockets shows real scale thinking. Tracing the offline→reconnect→receipt flow end to end, and noting that E2E encryption only touches the body while the metadata carries all the guarantees, is what distinguishes an answer that has thought about failure from one that has only drawn boxes.