WebSocket Architect
FreeOfficialDesign WebSocket and real-time communication systems: connection management, reconnection, message protocols, and scaling.
Model requirements
standard
16k tokens
Skill instructions
When to use
Use this skill when designing a real-time feature — live dashboards, collaborative editing, chat, notifications, multiplayer, streaming updates — where WebSocket (or Socket.io/SignalR) is the transport. WebSockets introduce stateful connection management, reconnection, backpressure, and horizontal-scaling challenges that request-response HTTP does not. Trigger when the user mentions WebSocket design, real-time architecture, Socket.io scaling, connection management, or server-sent events.
Inputs to gather
- The real-time use case: notifications, chat, collaboration, live data, presence
- Expected connection count and message rate per connection
- Message direction: mostly server-to-client, mostly client-to-server, or bidirectional
- Whether messages need delivery guarantees (at-least-once, ordered) or fire-and-forget is acceptable
- The deployment topology: single server, cluster, multi-region
- Authentication model for connections (token in handshake, cookie, subprotocol)
- Client platforms: browser, mobile, desktop, IoT
- Whether the data is fan-out (one source, many subscribers) or point-to-point
Procedure
- Decide if WebSocket is actually the right transport. For pure server-to-client push (notifications, live updates), Server-Sent Events (SSE) is simpler and auto-reconnects over HTTP/2. For bidirectional or high-frequency, WebSocket is appropriate. For mobile push to offline devices, you still need FCM/APNs regardless. Don't use WebSocket where SSE or long-polling suffices.
- Design the connection lifecycle. Define the handshake (auth token validation, origin check, protocol negotiation), the open state (subscription registration), the close path (clean vs abrupt, cleanup of server-side state), and timeouts (idle ping/pong to detect dead connections). Unmanaged connections accumulate as zombie state that exhausts resources.
- Build reconnection into the client from day one. Connections will drop — networks fluctuate, servers restart, load balancers idle-timeout. The client must detect drops (missed pings), reconnect with exponential backoff and jitter, re-authenticate, re-subscribe to channels, and replay missed messages if delivery guarantees require it. Without this, every transient drop loses the session.
- Define the message protocol. Specify the wire format (JSON, MessagePack, protobuf), the envelope (type, id, channel/topic, payload, timestamp), and the message types (subscribe, unsubscribe, event, ack, error). Version the protocol from the start. For typed safety, generate client and server stubs from a shared schema (protobuf, async-api).
- Handle backpressure and slow consumers. A slow client that can't drain its receive buffer will cause server memory to grow or the connection to stall. Implement a per-connection send queue with a cap; when the cap is exceeded, drop the message (fire-and-forget), close the connection, or apply flow control depending on the semantics. Never let one slow client OOM the server.
- Plan horizontal scaling with a pub/sub backplane. A client connected to server A must receive a message published by a client on server B. Use Redis Pub/Sub, NATS, or a message broker as the backplane so any server can publish to a channel and all servers with subscribers forward to their clients. Track which server holds which connection (sticky sessions or a connection registry) for point-to-point delivery.
- Manage subscriptions and fan-out efficiently. Maintain a server-side channel/topic → connections index for O(1) fan-out. For presence and collaboration, track per-channel membership and broadcast join/leave events. Cap subscriptions per connection and validate authorization on every subscribe, not just on connect — a user's permissions change over time.
- Add observability for connections and messages. Track active connections, message rates, reconnect rates, message latency, and backpressure events as metrics. Log connection lifecycle events with a connection id for tracing a single session's behavior. A real-time system without these metrics is impossible to debug in production.
- Secure the connection. Authenticate in the handshake (token in query string or subprotocol for browser limitations), validate origin, enforce per-connection and per-channel rate limits, and treat every inbound message as untrusted input. Use wss:// (TLS) in production. Re-validate authorization on subscribe and on every inbound message.
Output format
A real-time architecture document with: the transport choice rationale, the connection lifecycle state machine, the message protocol spec (envelope and types), the reconnection and replay client design, the scaling backplane design with the subscription index, the backpressure handling strategy, the auth and authorization model, and the observability metrics.
Common pitfalls
- Assuming connections are reliable and not building reconnection and resubscription, so every network blip silently drops the user's real-time updates.
- Scaling to multiple servers without a pub/sub backplane, so messages published on one server never reach clients connected to another.
- Letting a slow consumer's send queue grow unbounded, OOMing the server.
- Authenticating only at handshake, then a user's permissions change and they keep receiving data they no longer should.
- Using WebSocket for server-to-client-only push when SSE would be simpler and more robust.
- Not pinging idle connections, so dead half-open connections accumulate and exhaust connection slots.