Design: Real-Time Chat Flashcards

ADVANCED › System Design

Why is WebSocket the usual primary transport for a chat app, and what backs it up?
WebSocket gives a single persistent, full-duplex connection with low per-message overhead and server-push, ideal for foreground real-time chat. It is backed up by FCM push to deliver/wake the app when the socket is closed (backgrounded or killed).
How does optimistic send work without creating duplicate messages on retry?
The client generates a stable clientMessageId, inserts the message locally as 'pending', and renders it immediately. The same id is sent on every retry; the server treats it as an idempotency key and dedupes, then echoes back the canonical server id/sequence.
What should be authoritative for message ordering, and why not the device clock?
A server-assigned sequence number (or server timestamp) is authoritative. Client wall-clocks drift and can be wrong, so they cannot be trusted for global ordering across participants and devices; the client reorders to match the server sequence.
Distinguish the delivery states and who sets each.
pending (queued locally), sent (server ACKed receipt), delivered (recipient's device received it), read (recipient opened/viewed it). The sender sets pending; server ACK drives sent; recipient device emits delivered and read receipts back through the channel.
How do you build a reliable offline send queue on Android?
Persist unsent messages in Room with a pending status, attempt send over the live socket, and on failure retry with exponential backoff. Use WorkManager (or a reconnect handler) to flush the queue when connectivity returns; idempotency keys make replays safe.
Why use cursor/keyset pagination instead of OFFSET for chat history?
Cursor pagination requests messages before/after a stable boundary (message id or timestamp), so newly inserted messages don't cause page drift or duplicates/skips. OFFSET shifts as rows are added and gets slower for deep pages.
Per Android's architecture guidance, what is the single source of truth for the message list?
The local persistent database (Room) is the SSOT. The repository writes network/socket events into the DB, and the UI observes it via Flow/StateFlow, so the screen renders identically online or offline (offline-first, unidirectional data flow).
How do you keep typing indicators and presence cheap on battery and bandwidth?
Throttle/debounce them, batch with other low-priority signals, and auto-expire typing after a few seconds of inactivity. They are best-effort QoS-low events, sent below message traffic, never one network call per keystroke.
Why can't you just keep a WebSocket open to receive messages in the background?
Doze and App Standby suspend network and background work when the app isn't foreground, and the OS reclaims processes, so the socket dies. A high-priority FCM data message is the sanctioned way to wake the app and fetch/show the new message.

Back to Design: Real-Time Chat