FSD Frontend System Design

Part I β€” The Pipes Β· Lesson 2.4

Web Sockets

In one lineOne HTTP request upgrades into a persistent two-way pipe that stays open for the session.

Where you've seen itWhatsApp Web β€” the "typing…" indicator only works because the browser can send without being asked.

  • Time16 min
  • DiagramUpgrade handshake + duplex frames + reconnect state machine
  • Chapter2 Β· Communication

Diagram

diagram
THE UPGRADE β€” starts as HTTP, then stops being HTTP

  Client                                Server
    β”‚                                     β”‚
    │── GET /ws  HTTP/1.1 ───────────────►│
    β”‚   Upgrade: websocket                β”‚
    β”‚   Connection: Upgrade               β”‚
    β”‚   Sec-WebSocket-Key: dGhlIHNh...    β”‚
    β”‚                                     β”‚
    │◄─ 101 Switching Protocols ──────────│   ← not 200
    β”‚   Sec-WebSocket-Accept: s3pPLM...   β”‚
    β”‚                                     β”‚
    β•žβ•β•β•β•β•β•β•β•β• ws:// frames, both ways ═══║
    │──── {type:"typing"} ───────────────►│
    │◄─── {type:"message"} ───────────────│
    │◄─── {type:"presence"} ──────────────│
    │──── ping ──────────────────────────►│   keepalive
diagram
CONNECTION STATE MACHINE β€” the part interviews actually ask about

  [connecting] ──open──► [open] ──close/error──► [reconnecting]
       β–²                   β”‚                          β”‚
       β”‚                   β”‚ send()                   β”‚ backoff
       β”‚                   β–Ό                          β”‚ 1s,2s,4s,8s…
       β”‚              queue if not open                β”‚
       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                        on success: replay queue, resubscribe,
                                    fetch missed messages by cursor

How it works

  1. Client opens new WebSocket(url); the browser sends an HTTP Upgrade request.
  2. Server replies 101; the TCP connection is now a framed, full-duplex channel.
  3. Either side sends messages at any time β€” text or binary, no headers per message.
  4. Heartbeats (ping/pong) detect dead connections that TCP hasn't noticed.
  5. On drop, reconnect with exponential backoff + jitter, then re-authenticate, re-subscribe, and fetch what you missed.
js
socket.onclose = () => {
  delay = Math.min(delay * 2, 30_000) + Math.random() * 1000;
  setTimeout(connect, delay);          // never reconnect in a tight loop
};

Trade-offs

Use whenAvoid when
Both sides send, oftenOnly the server has news β†’ SSE
Sub-second latency is the featureUpdates are minutes apart β†’ poll
Chat, cursors, games, live collabYou need HTTP caching or CDN

What you now own: authentication (the handshake carries cookies, not Authorization headers β€” use a ticket), sticky sessions or a pub/sub backplane (Redis) so any server can reach any client, per-connection memory limits, and message ordering after reconnect.

Interview angle

"Your chat works locally and breaks behind the company proxy. Why?"

  • Some proxies strip the Upgrade header or kill idle connections; wss:// (TLS) survives far more of them.
  • Add heartbeats so a silently dead connection is detected, and always ship an SSE or long-poll fallback.
  • Behind a load balancer, a reconnect can land on a different server β€” you need a shared pub/sub layer, not in-memory state.

Recap

  • One handshake, then a permanent duplex pipe with tiny per-message overhead.
  • The protocol is the easy part; reconnect, resubscribe, and replay are the design.
  • Only pay for duplex when the client genuinely needs to talk back.