Hermes Wiki
Developer/CommunicationPatterns/Protocols/LongPolling/Fundamentals/long-polling-fundamentals-and-when-it-still-earns-its-keep

Long Polling Fundamentals and When It Still Earns Its Keep

Concept

Plain HTTP request/response gives a client exactly one way to learn something changed on the server: ask. Short polling — issue a request every N seconds, get back "nothing new" most of the time — is the naive way to simulate real-time updates over that request/response model, and it trades latency against load in a bad way: poll fast for low latency and burn requests/connections on mostly-empty responses; poll slow to save load and updates arrive late.

Long polling (part of the broader Comet family of techniques, the term coined in 2006 for server-push-over-HTTP approaches) changes the shape of that tradeoff rather than the underlying constraint. The client makes a request exactly as before, but the server does not respond immediately — it holds the connection open until there is new data to report, or until a timeout elapses with nothing to report. The moment the server responds (with data, or with an empty timeout response), the client immediately issues a new long-poll request. From the client's perspective this looks like a sequence of ordinary HTTP requests; from the server's perspective, each connection is held open far longer than a normal request, waiting on an event rather than blocking on I/O.

This gets near-real-time delivery latency (the server responds as soon as data exists, not on the next poll interval) while still working over plain HTTP — no protocol upgrade, no special server support, no infrastructure component that needs to support persistent full-duplex connections. That property is exactly why long polling predates, and today mostly survives as a fallback beneath, WebSockets (a full-duplex, persistent TCP connection reached via an HTTP Upgrade handshake) and Server-Sent Events (a one-way, server-to-client HTTP stream using a simple standardized text format). Both of those are strictly better than long polling when available — lower overhead (no repeated HTTP request/response framing per update), true push rather than a polling loop underneath — but both require the network path to actually support them, and long polling's advantage is that "plain HTTP works" is a much weaker requirement than "the Upgrade header and persistent connections survive every proxy and load balancer in the path."

Tradeoffs

Technique Latency Server cost per idle client Works everywhere plain HTTP works?
Short polling Bounded by poll interval (worse for lower load) Low per-request, but frequent Yes
Long polling Near-immediate (bounded by held-open timeout) One held-open connection/thread or async handle per waiting client Yes
Server-Sent Events Immediate (server pushes as data arrives) One held-open connection per client, but no repeated request/response framing Mostly — plain HTTP, but some proxies buffer/strip streaming responses
WebSockets Immediate, bidirectional One held-open connection per client, lowest per-message overhead No — needs Upgrade support end-to-end; some corporate proxies strip it

The axis that actually decides between these in practice is rarely raw performance — it's what the network path between client and server will tolerate. A client population behind unknown corporate proxies, older enterprise networking gear, or restrictive infrastructure that strips Upgrade headers and buffers streaming responses can silently break WebSockets and SSE while plain long-polling keeps working, because it never asks for anything beyond a normal request/response.

When to use / when not to

  • Use as a fallback beneath WebSockets or SSE, not as the primary transport, for any client population where network compatibility can't be guaranteed — real-time libraries (Socket.IO, and realtime infrastructure providers like Ably) detect when the preferred transport fails or degrades and fall back to long polling automatically, and some intentionally start on a long-polling/Comet connection and upgrade to WebSockets once it's confirmed to work, precisely because a connection that works for 100% of clients immediately beats one that's better but fails silently for a subset.
  • Use as the primary and only transport only when SSE and WebSockets are both genuinely unavailable — very old client requirements, or backend infrastructure that categorically cannot hold persistent duplex connections but can hold ordinary requests open.
  • Don't reach for long polling by default for new real-time features — SSE is simpler to implement than WebSockets and sufficient for one-way server-to-client updates (notifications, live counters, status updates), and WebSockets are necessary only when the client also needs to push frequently (chat, collaborative editing, multiplayer). Long polling is strictly worse than both when either is available.
  • Don't use long polling assuming it's free of server resource cost — a held-open connection per waiting client still consumes a connection slot (and a thread, in a threaded server model) for the duration of the hold, which is the same resource-exhaustion shape a synchronous long-running request has; an async/event-loop server model handles many held-open long-polls far more cheaply than a thread-per-connection one.

Common pitfall

Assuming long polling is "basically the same" as short polling with a longer timeout, and therefore free to add without re-thinking server capacity. The failure mode is specific: a long-poll connection is held open for the duration of the wait, not the duration of a normal request, so the number of concurrent held-open connections scales with the number of simultaneously-waiting clients, not with request rate. A server sized for short-request-response traffic can run out of available connections/threads under a load of long-polling clients that would look modest measured in requests-per-second, because the metric that matters (concurrent open connections) isn't the one a request-rate dashboard shows.

Engineering Lens

The decision that matters isn't "long polling vs WebSockets" in isolation — it's naming, up front, what the network path between the client population and the server can actually be relied on to support, and designing the fallback chain (WebSockets → SSE → long polling, or SSE → long polling if bidirectional push was never needed) rather than picking one transport and hoping it works everywhere. Real-time infrastructure providers' own architecture choices are the tell here: providers whose whole business is realtime delivery still default to starting some connections on long polling and upgrading, specifically because "works for every client immediately" beats "the theoretically best transport, when it works."

Sources

Hermes Wiki