# Low Level Design: Long Polling, SSE, and WebSocket

Source: https://www.techinterview.org/post/3233473115/lld-long-polling-sse-websocket/
Updated: 2026-04-18 · techinterview.org

Real-time communication between client and server requires pushing data from server to client without the client repeatedly polling. Three main patterns exist: long polling (HTTP-based, simplest), Server-Sent Events (SSE, one-way streaming), and WebSockets (full-duplex). The choice depends on communication direction requirements, infrastructure constraints, and client capabilities.

## Long Polling

The client sends an HTTP request; the server holds the connection open until an event occurs or a timeout is reached (typically 30-60 seconds). When the server responds, the client immediately sends a new request. This simulates push over standard HTTP without persistent connections. Drawbacks: each client ties up a server thread or file descriptor; 30-second timeouts generate high reconnect overhead; no multiplexing of multiple event streams on one connection.

## Server-Sent Events (SSE)

SSE uses a persistent HTTP connection with Content-Type: text/event-stream. The server sends events as text lines: "data: {json}nn". The browser EventSource API reconnects automatically with the Last-Event-ID header so the server can resume from where the client left off. SSE is one-directional (server to client only). It works through HTTP/2, supports multiplexing, and traverses proxies and firewalls more reliably than WebSockets. Best for dashboards, notifications, and live feeds where the client doesn't need to send data back.

## WebSockets

WebSocket upgrades an HTTP connection to a persistent, full-duplex TCP channel. Both client and server can send messages at any time. The upgrade handshake uses HTTP Upgrade header. WebSocket frames have minimal overhead (2-14 bytes per frame vs full HTTP headers). Best for interactive applications: chat, collaborative editing, online games, trading terminals, where bidirectional low-latency communication is required.

## WebSocket Connection Lifecycle

Client opens connection: GET /ws HTTP/1.1 with Upgrade: websocket, Sec-WebSocket-Key. Server responds 101 Switching Protocols. Both sides exchange frames. Connection terminates with a close frame (code + reason). Implement heartbeat (ping/pong frames every 30s) to detect dead connections through NAT and load balancers that timeout idle TCP connections. Reconnect with exponential backoff on disconnect.

## Scaling WebSocket Servers

WebSocket connections are long-lived; a single server handles tens of thousands of concurrent connections using non-blocking I/O (Node.js, Netty, Go goroutines). Load balancers must support sticky sessions (route reconnecting clients to the same server) or use a shared pub/sub backend (Redis Pub/Sub, Kafka) so any server can receive messages intended for connections held by other servers. A message broker decouples senders from the specific server holding each connection.

## Presence and Connection State

Track which users are online by maintaining a connection registry: on connect, write {user_id, server_id, connected_at} to Redis. On disconnect, delete the entry. Set a TTL on the entry and refresh on each heartbeat to handle abrupt disconnections. Query the registry to determine if a user is online before sending a push notification (no point pushing if user is actively connected to WebSocket). The registry also enables fanout: find all connections for a user and deliver to each.

## Choosing the Right Pattern

Use long polling when: you can't change server infrastructure, need compatibility with strict firewalls, have low message frequency (<1/minute). Use SSE when: communication is server-to-client only, you want simplicity and automatic reconnection, you need to pass through HTTP/2 proxies. Use WebSockets when: you need bidirectional communication, low latency (<100ms), high message frequency, or rich interactive features. Most modern real-time applications (chat, collaboration, gaming) use WebSockets.
