Real-Time Systems
WebSockets vs Polling for Real-Time Services
When polling is enough, when WebSockets earn their operational cost, connection management at scale, and hybrid patterns for live maps, offers, and status fan-out.
SystoBase Engineering · · 14 min
Key takeaways
- Polling is underrated for early scale — simpler ops, easier caching, sufficient for many UX paths.
- WebSockets shine for high-frequency fan-out (live location, live status) with many concurrent subscribers.
- Industry pattern: WebSockets everywhere day one; SystoBase recommendation: poll until measured pain, then targeted upgrade.
- Connection state is infrastructure — heartbeats, reconnect storms, auth refresh.
- Redis pub/sub or streams bridge hot ingestion to socket nodes.
- Always authorize subscription by resource ID — no global firehose.
Product requirements first
Real-time is not binary — a user waiting for acceptance may tolerate a 2–3s poll interval; a user watching a live map wants sub-second updates. Define latency budgets per screen before choosing WebSockets. Live ops dashboards, logistics tracking, marketplace status, and mobility apps all face the same transport choice.
Time-sensitive offers may need push notification plus an in-app modal — transport to the device is FCM/APNs as much as WebSocket.
Industry pattern: uniform real-time stack. SystoBase recommendation: per-feature transport choice documented in an ADR with expected concurrent connections.
Polling patterns that work
ETag or version-based polling: client sends If-None-Match, server returns 304 when domain state is unchanged — cuts payload on waiting screens.
Adaptive interval: back off when idle, tighten near expected state-change windows after assignment.
Polling scales horizontally with a stateless API and Redis cache of the resource snapshot — no sticky sessions required.
Where WebSockets win
Live location on a map at 1–2 updates/sec justifies a persistent connection — polling at that rate wastes battery and bandwidth. Courier tracking and fleet maps are common cases; the service pattern is the same.
Operator war rooms watching many active jobs — multiplex channels with authorization per resource.
Industry pattern: single global socket per app. SystoBase recommendation: namespaced channels (/jobs/{id} or /orders/{id}) with subscribe auth validating the caller’s role.
Connection management
Heartbeats detect dead connections; server-side sweeps clear stale sessions. Mobile backgrounding drops connections — clients must resync state on resume.
Reconnect storms after deploy: jitter backoff, rate-limit socket accepts at the load balancer, readiness probes before cutting old pods.
Auth tokens expire — refresh without dropping the channel, or re-subscribe with a new token seamlessly.
Hybrid architecture
Common pattern: poll status until accepted, then upgrade to WebSocket for the live-tracking phase only — reduces concurrent socket count during peak waiting.
Location pipeline: mobile → ingestion → Redis GEO → pub/sub to socket fleet → client. Keep PostgreSQL off the hot read path for map pins.
Industry pattern: socket server hits the DB every message. SystoBase recommendation: push deltas from cache with sequence numbers for client ordering.
Failure modes
Sticky session misconfiguration routes a client to a node without their channel — ghost disconnects. Prefer Redis-backed pub/sub fan-out with stateless socket nodes.
Memory leaks in connection handlers take out nodes silently — monitor open fds and heap per instance.
Fallback to polling when the socket fails — the product must degrade gracefully, not blank the UI.
Decision rubric
Choose polling if: update frequency < 0.5 Hz, few concurrent subscribers per resource, team lacks socket ops experience, MVP timeline is tight.
Choose WebSockets if: live map tracking UX, many simultaneous field updates, bi-directional low latency needed, measured poll load exceeds socket ops cost.
Revisit the decision at 10× concurrency — polling cost rises linearly; sockets cost rises with connections but save bandwidth.