Understanding the problem
WhatsApp is a messaging service for send/receive of messages (and calls) from phones and computers. Interviewers don't want every Messenger feature — lock the core path, then deep-dive deliverability and scale. Ask how the product is used (mostly 1:1 vs large groups, messages/day) — those answers drive partitioning later.
2–100 participants.
Offline ≤30 days.
Cross-host delivery.
Presigned blobs.
Pair with Delivery framework, Real-time updates, Large blobs, Redis, and News feed (celebrity / fan-out cousin).
Functional requirements
Non-functional requirements
Planning the approach
Recognize two halves early: durable delivery (Inbox / Messages) and realtime push (WebSockets + pub/sub). Solve the general group case; 1:1 falls out. Start single-host so mechanics are clear — then scale out. Scaling first without understanding delivery is how you paint yourself into a corner.
- Entities + WebSocket command API.
- HLD per FR: create chat → send → offline inbox → media.
- Deep dives: multi-host pub/sub, multi-device, heartbeats, gap detection, last-seen.
- Level check: mid owns breadth; senior owns routing/robustness; staff drives failure modes.
Core entities
Nouns for the rest of the interview — not a grading rubric, but a broken foundation if wrong.
API — WebSocket commands
Chat is high-frequency bi-directional traffic — a poor fit for request/response REST. Use WebSockets over TLS (or a custom protocol over TLS TCP). Clients open a socket and exchange commands. Pattern deep dive: Real-time updates.
// -> createChat { participants[], name } -> { chatId }
// -> sendMessage { chatId, message, attachments[] } -> { status, messageId }
// -> getAttachmentTarget { ... } -> { uploadUrl }
// -> modifyChatParticipants { chatId, userId, ADD|REMOVE }
// <- chatUpdate / newMessage ... client replies RECEIVED (ACK)
HLD — create group chats
Chat Service behind an L4 load balancer (WebSockets; no L7 path routing needed). Persist Chat + ChatParticipant rows in DynamoDB (or similar KV).
- Chat — primary key
chatId. - ChatParticipant — PK
chatId, SKparticipantId(list members). - GSI — PK
participantId, SKchatId(list a user's chats). - Near 100 participants, batch writes; small chats can use a single transaction.
HLD — send/receive (single host first)
Start with one Chat Server. Say out loud that it's not scalable — then keep the mechanics clean. In-memory map: userId → WebSocket.
- Client sends
sendMessage. - Lookup participants via ChatParticipant.
- Push
newMessageon each participant's socket (assumes everyone online on this host).
HLD — offline delivery (Inbox)
Persist messages and keep an Inbox of undelivered message IDs per recipient. Write durability before attempting push.
- Write Message row + Inbox entries for each recipient.
- Return SUCCESS + messageId to sender.
- Attempt
newMessageon connected sockets; clients ACK → delete Inbox rows. - On connect: drain Inbox → fetch Messages → push → ACK → delete.
- TTL on Inbox/Messages (~30 days) for cleanup.
HLD — media attachments
Media is bandwidth- and storage-heavy. Don't shove blobs through the chat WebSocket into DynamoDB. WhatsApp-style: attachments via a separate HTTP/blob path.
- Bad — media over WS into DB (cripples chat hosts; DBs hate big binaries).
- Better — Chat Server forwards to blob store (TTL 30d); still a wasted hop.
- Best —
getAttachmentTargetreturns presigned upload URL; client uploads direct; message carries opaque URL; recipients download via presigned GET. CDN optional (max 100 participants).
Same pattern as Handling large blobs / Dropbox.
Deep dive — billions of users / multi-host
~1B users → ~200M connected. Lore: WhatsApp ~1–2M users/host → hundreds of chat servers. Sender and recipient often land on different hosts — in-memory maps don't help.
Partition by user vs chat? WhatsApp is 1:1-dominated with a hard 100-participant cap. Per-user channels avoid hundreds of redundant chat subscriptions. For large chats (e.g. >25), adaptively also subscribe to a chat-level channel and publish there — briefly dual-publish while membership converges. Celebrity-problem cousin of news-feed fan-out.
Alternatives (sticky LB, consistent hash of user→server) live in Real-time updates. Pub/Sub is the usual interview default once you leave one box.
Deep dive — multiple clients per user
Phone got the message; laptop was asleep — laptop must catch up. User-level Inbox is no longer enough.
- Add Clients table keyed by userId.
- Resolve participants → all active clients; deliver + ACK each.
- Inbox becomes per-client.
- Deactivate dead clients so you don't store forever.
- Pub/Sub topics unchanged (still userId).
Deep dive — dead sockets, lost pub/sub, order
- Dead WebSocket — TCP keepalive is minutes; too slow. Prefer ping/pong every 10–30s (close on miss). Also: ACK timeout on delivery (500–2000ms) then retry / close.
- Redis Pub/Sub loss — at-most-once. Durability = Inbox-before-publish. Detect gaps with per-user monotonic seq (Redis INCR); include seq on heartbeats; client syncs Inbox. Periodic poll as backstop (tune interval vs load).
- Out-of-order — don't wait for perfect order. NTP-synced servers stamp receive time; clients display by server timestamp. Occasional "pop-in above" is acceptable UX.
Deep dive — last seen
Don't write lastSeen on every heartbeat — that's a write storm for stale data.
- On disconnect, conditional-update LastSeen table (only if newer timestamp).
- Client sends
getLastSeen; server reads DB and publishes probe to target user channel. - If target host has an open socket, reply
ONLINE; else show disconnect time. - Client merges DATABASE vs SERVER reporters (ONLINE wins).
Final design
Cost and performance levers
What interviewers expect by level
Mid: working spine + offline inbox. Senior: multi-host + robustness. Staff: anticipate failures and keep the design lean like WhatsApp's ops reputation.
Wrapping up
WhatsApp interviews reward deliverability under flaky networks and connection-dense scale, not feature laundry lists. Inbox-before-publish, client ACKs, pub/sub across hosts, and media off the chat path get you most of the way — then harden with heartbeats, sequences, and multi-device inboxes.
Related: Delivery framework · Real-time updates · Large blobs · Redis · News feed · Networking · Common patterns.