WebSockets and Long Polling
HTTP was designed around a request-response model: the client asks, the server answers, the connection is done. That model breaks down for chat apps, live dashboards, multiplayer games, and stock tickers, where the server needs to push data the instant it becomes available. Over the years, three broad strategies emerged to bridge this gap: short polling, long polling, and WebSockets, each trading off latency, server load, and implementation complexity differently. The simplest of the three, short polling, has the client send a request every N seconds asking 'anything new?', with the server replying immediately whether or not there's anything to report; it's trivial to implement and works through any proxy or firewall, but it wastes enormous bandwidth and server capacity on empty responses, and the polling interval directly bounds latency — halve the interval and you double the request volume for marginally fresher data. It's rarely acceptable for anything beyond low-frequency status checks, which is why long polling and WebSockets exist. Understanding when to reach for each is a recurring system design decision, especially for any 'real-time feature' requirement.
Cricket analogy: Like a fan texting a friend at the stadium every minute asking 'any wicket yet?' and getting 'no' most of the time, short polling wastes effort on empty replies when the friend could just text the moment a wicket actually falls.
Long Polling
Long polling improves on this by having the server hold the request open — not responding immediately — until new data is available or a timeout (typically 20-60 seconds) elapses. The moment data arrives, the server responds and closes the connection; the client immediately reopens a new request. This collapses the latency-vs-request-volume tradeoff of short polling: updates arrive close to instantly, and idle periods generate far fewer requests. The cost is that each held-open connection consumes a server thread or event-loop slot for a long time, and you still pay full HTTP header overhead on every reconnect cycle.
Cricket analogy: Like a scorer's assistant staying on the phone line with the ground and only speaking up the instant a wicket falls instead of hanging up and redialing every minute, long polling holds the connection open, delivering near-instant news but tying up that phone line the whole time.
WebSockets
WebSockets solve the underlying problem directly: after an HTTP handshake (the Upgrade header) the TCP connection is repurposed into a persistent, full-duplex channel where either side can send frames at any time with minimal per-message overhead. There's no repeated reconnect, no wasted headers, and true bidirectional push — the server can send unprompted, and the client can send without waiting for a response. This makes WebSockets the natural choice for chat, collaborative editing, live multiplayer state, and trading platforms. The cost is operational: connections are long-lived and stateful, so load balancers need sticky routing or a shared pub-sub backplane, connection counts become a capacity dimension in their own right, and reconnect/backoff logic must be handled explicitly on flaky networks.
Cricket analogy: Like a stadium's dedicated walkie-talkie channel between the scorer and the broadcast booth that stays open the entire match, letting either side speak instantly at any time without redialing, though it ties up a channel and needs a clear protocol if the signal drops mid-over.
Short polling:
Client -> GET /updates -> Server (returns instantly, often empty)
[repeat every N seconds regardless of activity]
Long polling:
Client -> GET /updates -> Server (holds request open)
... waits for event or timeout ...
Client <- 200 {data} <- Server (closes)
Client -> GET /updates -> Server [reopen immediately]
WebSocket:
Client -> GET /ws (Upgrade: websocket) -> Server
Client <- 101 Switching Protocols <- Server
[single TCP connection now full-duplex]
Client <-> frame <-> Server (either side, any time, low overhead)Slack's real-time architecture historically layered long polling as a fallback for clients on networks that block WebSocket upgrades (some corporate proxies strip the Upgrade header), while defaulting to WebSockets for the primary message stream. This kind of graceful degradation — WebSocket first, long polling as fallback, short polling as last resort — is a common production pattern rather than an either/or choice.
A common mistake is assuming WebSockets are 'free' once established. Because they are stateful and pinned to a specific server process, a naive horizontal scale-out breaks unless you add sticky sessions at the load balancer or route messages between server instances through a shared broker (e.g. Redis pub-sub). Forgetting this means messages silently fail to reach clients connected to a different server instance than the one that produced the event.
- Short polling is simple but wastes bandwidth and bounds latency to the poll interval.
- Long polling holds the HTTP request open until data is ready, cutting both latency and empty-response overhead.
- WebSockets upgrade a single TCP connection into a persistent, full-duplex, low-overhead channel.
- WebSockets require sticky load balancing or a shared pub-sub layer to fan out messages across server instances.
- Real production systems often layer WebSocket-first with long-polling fallback for restrictive networks.
- Choice depends on message frequency, latency requirements, and directionality (server push vs bidirectional).
Practice what you learned
1. What is the primary drawback of short polling compared to long polling?
2. How does long polling reduce latency compared to short polling?
3. What must happen at the load balancer to scale WebSocket servers horizontally?
4. Which protocol feature allows a WebSocket connection to begin?
5. Why might a production system offer long polling as a fallback even when WebSockets are the default?
Was this page helpful?
You May Also Like
Message Queues Explained
Message queues decouple producers from consumers by buffering work as discrete messages, enabling asynchronous processing, load leveling, and resilience to downstream slowdowns.
Pub/Sub Architecture
Publish-subscribe architecture decouples message producers from an unknown, dynamic set of consumers by routing messages through named topics rather than direct point-to-point links.
Designing a Chat Application
Covers the architecture behind real-time messaging apps: persistent connections, message delivery guarantees, ordering, presence, and multi-device synchronization.
Load Balancing Algorithms
Surveys the algorithms load balancers use to distribute traffic across backend servers, from simple round robin to adaptive least-connections and consistent hashing.
Related Reading
Related Study Notes in Software Engineering
Browse all study notesMicroservices Study Notes
Software Architecture · 30 topics
Software EngineeringTesting & TDD Study Notes
Software Testing · 30 topics
Software EngineeringDesign Patterns Study Notes
Software Design · 30 topics
Software EngineeringSoftware Engineering Study Notes
Python · 40 topics
Software EngineeringGit & Version Control Study Notes
Bash · 40 topics