Skip to main content

Quiz: Real-Time Systems

Covers transport choice, sequence numbers, deduplication, missed-event replay, and reconnection. Reference: ADR: Real-Time Communication · ADR: WebSocket Reliability Protocol.


Question 1: Transport choice

Senior

WebSocket vs Server-Sent Events vs polling, how do you choose, and why WebSocket here?
Show answer
  • Polling: simplest, but trades latency for load: you're either too slow or hammering the server with mostly-empty requests. Fine for low-frequency, non-urgent data.
  • SSE: server→client streaming over HTTP, auto-reconnect built in. Great when only the server pushes. But it's one-directional.
  • WebSocket: full-duplex. Chosen here because the client also needs to send (subscribe with lastSeq, pings) and future trading features need low-latency bidirectional messaging. The cost is that reliability (reconnect, replay, dedup) is now your job, which is why the reliability protocol exists.

The honest framing: WebSocket isn't "better," it's the right tool when you need bidirectional and you're willing to own the reliability layer.


Question 2: Sequence numbers

Senior

Every event carries a monotonically increasing seq. What does the client do with it, and what failure does it catch?
Show answer

The client tracks lastSeq. When an event arrives with seq > lastSeq + 1, it knows it missed events in between (received − expected of them) and logs/handles a gap. Without seq numbers, a dropped frame is invisible: the buyer just silently never sees an update, and the UI is wrong with no signal.

The recovery half: on reconnect the client sends { type: 'subscribe', lastSeq: N }, and the server replays everything with seq > N. So seq numbers turn "we might have missed something, who knows" into "we missed exactly 43 and 44, please resend," detectable and recoverable.


Question 3: Deduplication

Senior

The client keeps a bounded set of seen eventIds and drops repeats. What delivery guarantee makes this necessary?
Show answer

At-least-once delivery. Most messaging systems guarantee they'll deliver your message, but possibly more than once (e.g. a server resends because it didn't see your ack). That means the receiver must be idempotent: processing the same event twice must not double-apply it.

Dedup by eventId does that: seen it → drop it; new → record and process. The set is bounded (an LRU-lite window) so memory stays flat. Without it, a duplicated "balance updated" event could double a displayed change, or a duplicated transaction could appear twice in the feed.


Question 4: The reconnect storm

Staff

A server restarts and 50,000 clients drop at once. Why is naive immediate reconnect dangerous, and how do exponential backoff and jitter each help?
Show answer

If every client reconnects immediately, the server is hit by 50,000 simultaneous connections the instant it comes back (the thundering herd) and falls over again, producing an outage loop.

  • Exponential backoff (1s, 2s, 4s, 8s… capped at 30s) reduces the rate of retries per client, giving the server room to recover.
  • Jitter (a random 0–1s added to each delay) breaks synchronisation. Without it, all clients that dropped at the same instant retry at the same instants: backoff just moves the herd, it doesn't disperse it. Jitter smears reconnections across time so they arrive as a spread, not a spike.

You need both: backoff controls volume, jitter controls correlation.