protocol

WebSockets

A persistent bidirectional connection over HTTP — the right tool for server-initiated updates, and a stateful component in an otherwise stateless architecture.

websocketsrealtimeslackconnectionspresence

Definition

A WebSocket upgrades an HTTP connection into a long-lived bidirectional channel. The server can push without being polled, and the per-message overhead is small compared with an HTTP request.

What it changes architecturally

The important consequence is that your stateless service tier becomes stateful in one specific way: a connection is bound to one server process for its lifetime. That has consequences that surprise teams used to stateless request handling.

  • Deployments disconnect everyone. Every rolling deploy severs every connection on the replaced instance. Clients must reconnect with exponential backoff and jitter, or the reconnection is a self-inflicted thundering herd.
  • Load balancing is by connection, not by request. A newly added instance receives no traffic until clients reconnect, so a scale-out event does not relieve load on existing instances.
  • Routing a message to a user requires knowing which server holds their connection. This is the central design problem: either a shared registry of connection locations, or a message bus that every server subscribes to and filters.
  • Capacity is measured in concurrent connections and memory per connection, not in requests per second.

Industry example

Slack's real-time delivery makes the shape concrete. A message must reach every currently connected member of a channel within a second, and be available to those who reconnect hours later. Those are two different systems: live fan-out over persistent connections, and durable storage with an efficient catch-up protocol.

Three consequences follow. Connections are sharded so members of a channel are reachable from a bounded set of servers rather than requiring a global broadcast. Presence is its own subsystem — high write volume, low value per write, and explicitly allowed to be approximate, because nobody is harmed by a green dot three seconds stale. And very large channels are treated as a special case, because designing everything for the 100,000-member channel would make the three-person case absurdly expensive.

The catch-up protocol deserves emphasis: after any network blip, thousands of clients reconnect at once. If reconnection means "send me everything since my last cursor" and that is expensive, the recovery becomes a second outage.

Failure scenarios

  • Reconnect storms after a deployment or a network event, with no jitter.
  • Intermediaries dropping idle connections — proxies and firewalls commonly close after 60 seconds — requiring application-level heartbeats.
  • Memory per connection unmeasured, so an instance holds far fewer connections than assumed.
  • No backpressure toward a slow consumer, so the server buffers unboundedly and runs out of memory.
  • Assuming delivery. A connection can be open while messages are undelivered. Acknowledgement and a resume cursor are required for anything that matters.

Interview question

"A deployment drops 200,000 WebSocket connections. Describe what happens next and how you would make it safe."