Lesson 145 min read

Pattern: Real-time Updates

April 20, 2026

// TL;DR

When clients must see changes within seconds, you need a push strategy. Four options, cheapest to richest: short polling (ask every N seconds — simple, wasteful), long polling (hold the request until data arrives), SSE (a one-way server→client stream over HTTP, auto-reconnecting), and WebSocket (full-duplex, for chat and multiplayer). Pick by direction and latency. To scale push to millions, split the system: stateless connection servers hold the live sockets, and a pub/sub broker (Redis/Kafka) fans events out to the right servers, with a routing layer mapping each user to the server holding their connection. Always design reconnection and backfill — 'what did I miss while disconnected?'

Pattern: Real-time Updates

Many interview questions have a line buried in the requirements like “users should see new messages instantly” or “the dashboard updates in real time.” That single phrase changes the shape of your design: a plain request/response API cannot push, so you need a deliberate strategy for getting fresh data to clients. This is a pattern — a reusable technique that shows up across chat, notifications, live feeds, dashboards, collaborative tools and multiplayer games — so it is worth learning once, properly.

The core tension is that the web is built around clients pulling data, but real-time features need the server to push. Everything below is a different way to resolve that tension, trading simplicity against latency and connection cost.

In the interview: when you spot a real-time requirement, name the four options out loud and justify your pick in one sentence — “this is a one-way live feed, so SSE is enough; I would reach for WebSocket only if the client also needs to send a steady stream.” That signals you know the menu, not just the one tool you remember.

The menu: four ways to deliver updates

Comparison of short polling, long polling, SSE and WebSocket for delivering real-time updates

Short polling

The client asks “anything new?” on a fixed timer — every few seconds — and the server answers immediately, usually with nothing. It is trivial to build on top of a normal REST endpoint and needs no special infrastructure.

The cost is waste and lag. Most requests return empty, burning bandwidth and server capacity, and an update can sit for up to one poll interval before the client sees it. Short polling is the right answer only when near-real-time is acceptable and simplicity genuinely matters — a page that refreshes a status every 30 seconds, say.

Long polling

The client makes a request and the server holds it open until there is data (or a timeout), then responds; the client immediately reconnects. The user sees updates with almost no lag, and it still works over ordinary HTTP with no new protocol.

The downside is that every waiting client ties up a connection, and each update costs a full request/response round trip to re-establish. Long polling is a reasonable fallback where WebSocket is unavailable, but it has largely been superseded by SSE and WebSocket.

Server-Sent Events (SSE)

SSE opens a single long-lived HTTP connection over which the server streams events to the client as they happen. It is one-directional (server → client), text-based, runs over normal HTTP/2, and the browser’s EventSource automatically reconnects and can resume from the last event id.

GET /feed/stream        (client opens an EventSource)

<-- data: {"type":"new_post","id":9931}
<-- data: {"type":"new_post","id":9932}

SSE is the sweet spot for one-way live feeds: notifications, activity streams, price tickers, dashboards, progress bars. It is simpler than WebSocket and plays well with existing HTTP infrastructure.

WebSocket

WebSocket upgrades an HTTP connection into a persistent, full-duplex channel — both sides can send messages at any time with very low overhead. It is the right tool when the client needs to send a continuous stream too, not just receive: chat, collaborative editing, multiplayer games, live trading.

The cost is that it is stateful and heavier to operate. Each connection pins memory on a server, load balancers must support the upgrade and sticky routing, and you must handle reconnection and authentication on reconnect yourself.

Option Direction Latency Cost / complexity Use when
Short polling pull up to interval lowest near-real-time is fine
Long polling pull (held) low medium WebSocket unavailable
SSE server → client low medium one-way live feeds
WebSocket full-duplex lowest highest two-way, chat/games

Scaling the push

Choosing WebSocket or SSE is the easy part. The hard part is pushing to millions of simultaneously connected clients, and the key realization is that a connection is stateful: the live socket lives on one specific server. When an event is produced somewhere else in the system, you have to get it to exactly the servers holding the interested clients’ sockets.

A pub/sub broker fanning out events to WebSocket connection servers that each hold tens of thousands of client sockets

The standard architecture separates two concerns:

  • Connection servers — stateful nodes whose only job is to hold open sockets (tens of thousands each) and forward messages to the clients attached to them. They are horizontally scalable: add more as your connection count grows.
  • A pub/sub broker — a stateless fan-out layer (Redis Pub/Sub, Kafka, or a managed bus) that decouples whoever produces an event from whoever delivers it. A publisher writes an event once; the broker delivers it to every connection server that has a subscriber for it.

The missing piece is routing: when an event is destined for user 42, which connection server holds user 42’s socket? Two common approaches are to publish on a per-user (or per-room) channel that only the relevant connection servers subscribe to, or to keep a registry (in Redis) mapping user_id → connection_server that the fan-out consults. For broadcast scenarios like a public live feed, every connection server simply subscribes to the one channel.

Reconnection and backfill

Real connections drop — phones change networks, laptops sleep, servers restart. A robust real-time design treats disconnection as normal, not exceptional, and answers one question explicitly: “what did the client miss while it was gone?”

  • Resume from a cursor. The client remembers the id/timestamp of the last event it saw (SSE’s Last-Event-ID does this for you). On reconnect it sends that cursor, and the server replays everything since.
  • Backfill from the source of truth. For a chat app, on reconnect the client fetches any messages newer than its last-seen id from the regular (non-real-time) API, then resumes the live stream. The live channel delivers new events; a normal paginated query fills the gap.
  • Heartbeats and timeouts. Periodic pings detect dead connections quickly so the server can free resources and the client can reconnect, rather than silently believing it is still live.

In the interview: after you draw the connection servers and broker, add one line about reconnection and backfill. Candidates who forget it end up with a design that silently drops messages whenever a network blips — which is always.

Where this pattern shows up

  • Chat / messaging — WebSocket, per-conversation channels, backfill on reconnect.
  • Notifications and activity feeds — SSE or WebSocket fanning out from a pub/sub layer.
  • Live dashboards / metrics — SSE streaming aggregated updates.
  • Collaborative editing — WebSocket, broadcasting each edit to everyone in the document “room.”
  • Multiplayer / live trading — WebSocket for the lowest round-trip latency.

Key Takeaways

  1. A real-time requirement needs a push strategy. Normal request/response can’t push, so pick deliberately from the menu — short polling, long polling, SSE, WebSocket.

  2. Choose by direction and latency. SSE for one-way live feeds; WebSocket when the client also sends a steady stream (chat, games); polling only when near-real-time is acceptable.

  3. Connections are stateful — separate concerns to scale. Stateless connection servers hold the sockets; a pub/sub broker fans events out and decouples producers from delivery.

  4. Routing is the real problem. Map each user/room to the connection server holding their socket, via per-channel subscriptions or a registry.

  5. Design reconnection and backfill up front. Clients drop constantly; resume from a cursor and backfill the gap from the normal API so no updates are silently lost.