FSD Frontend System Design

Part I β€” The Pipes Β· Lesson 2.3

Long Polling

In one lineThe client asks, and the server holds the request open until it actually has news.

Where you've seen itOld Facebook Chat β€” messages appeared instantly, years before WebSockets existed in browsers.

  • Time13 min
  • DiagramSequence with a held connection, vs short polling timeline
  • Chapter2 Β· Communication

Diagram

diagram
Client                          Server
  β”‚                               β”‚
  │──── GET /messages ───────────►│
  β”‚                               β”‚  holds... (no data yet)
  β”‚        (waiting 25s)          β”‚
  β”‚                               β”‚  ◄── new message arrives
  │◄─────── 200 [msg] ────────────│
  β”‚                               β”‚
  │──── GET /messages ───────────►│  client immediately re-asks
  β”‚                               β”‚  holds...
  │◄────── 204 timeout ───────────│  after 30s, empty
  │──── GET /messages ───────────►│  re-asks again
diagram
SAME WALL CLOCK, FAR FEWER ROUND TRIPS

  SHORT POLL   0s────5s────10s───15s───20s───25s
               REQ   REQ   REQ   REQ   REQ   REQβ˜…    6 requests, 1 useful

  LONG POLL    0s─────────────────────────────25s
               REQ ──────── held β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Ίβ˜…      1 request, 1 useful
diagram
THE GAP β€” where messages get lost

  │◄── 200 [msg 7] ───│     response in flight
  β”‚                   β”‚  ← msg 8 arrives HERE, no open request
  │─── GET ──────────►│     client re-asks
                            msg 8 must be replayed, not dropped

  Fix: client sends its last seen id β†’ GET /messages?since=7

How it works

  1. Client sends a request.
  2. Server does not respond; it parks the request and registers the client as a listener.
  3. On new data β†’ respond immediately. On a 25–30s timeout β†’ respond empty.
  4. Client immediately opens the next request, passing the last id it saw.
  5. Server replays anything that arrived during the gap.

Trade-offs

Use whenAvoid when
Updates are infrequent and unpredictableUpdates are constant β†’ WebSocket
Proxies or firewalls block WebSocketsYou need client β†’ server push too
You want plain HTTP infrastructureServer can't hold many open connections

Server-side cost: every waiting client occupies a connection. A thread-per-request server dies at a few thousand; an event-loop server (Node, Go, nginx) handles far more. This is a backend constraint you should name out loud.

Interview angle

"Why not just poll every second instead?"

  • Short polling burns requests when nothing changed; long polling only answers when there's news.
  • The cost moves from bandwidth to held server connections and requires a non-blocking server.
  • Past roughly one update per second, reconnect churn beats the savings β€” switch to WebSocket or SSE.

Recap

  • Long polling is pull that feels like push.
  • Always pass a cursor (?since=) β€” the gap between responses drops messages otherwise.
  • Bridge technology: correct when WebSockets aren't available, not when they are.