"Session ID unknown" (HTTP 400) during rolling deploys: sticky sessions vs Redis adapter for Socket.IO
0 reputation · 13 Apr 2025, 23:27 UTC
0 reputation · 13 Apr 2025, 23:27 UTC
I'm planning a zero-downtime migration of a small Socket.IO application to a multi-node setup behind a load balancer. During rolling restarts, clients using the default transports can hit the Engine.IO error Session ID unknown (HTTP 400), because the handshake session lives in memory on the node that issued it and a subsequent polling request may land on a different node.
My understanding is that there are two documented mitigations with different trade-offs:
transports: ['websocket'] on the client so the connection stays pinned to one node for its lifetime — simple, but it removes the polling fallback for clients behind restrictive proxies.@socket.io/redis-adapter so room membership and broadcasts stay consistent across nodes during the cutover — extra infrastructure, and configuration keys differ between Socket.IO v2 and v3/v4.The application does use rooms and server-initiated broadcasts, but traffic is low enough that a brief degradation during deploys might be acceptable.
My questions:
Session ID unknown compared with sticky sessions on the default transports?30275 reputation · 14 Apr 2025, 03:30 UTC
1. Sticky sessions alone are not sufficient for cross-node rooms. Sticky sessions prevent Session ID unknown for the lifetime of a connection on a given node, but they do not make rooms work across nodes. Without an adapter, a server on node A only knows about sockets connected locally. Emitting to a room from node A will not reach clients that are connected to node B. If you can accept that during a rolling deploy some clients may miss broadcasts from nodes they are not pinned to, sticky sessions alone can be a temporary mitigation. Any requirement for reliable server-initiated broadcasts to all room members across the fleet effectively mandates a Redis adapter.
2. WebSocket-only reduces polling churn but does not remove the need for affinity. Engine.IO still performs an HTTP handshake before the upgrade. The handshake creates the session ID in memory on the node that handled it. With sticky sessions, the subsequent WebSocket frames stay on that node via TCP affinity. Without sticky sessions, a reconnect or the initial handshake can land on a different node and produce HTTP 400 Session ID unknown. Forcing transports:['websocket'] removes the long-polling fallback and the risk of a polling request bouncing mid-session, but it does not make the session portable across nodes.
3. Cross-node delivery can be verified without full production rollout. Start two server processes on different hosts/ports behind the same adapter configuration, connect clients to each node, join the same room, and emit from one node. With no adapter you will see the event only on the local node. With the Redis adapter installed on both processes you will see delivery to the remote client. Logging socket.id and io.of('/').adapter.rooms per process is a practical check.
Session ID unknown.@socket.io/redis-adapter provides inter-node pub/sub for events and room membership. It does not store the Engine.IO handshake session; the handshake must still reach a node that holds the session.During a rolling restart the load balancer routes a polling request for an existing session to a new pod that never performed the handshake. The new pod has no in-memory session, so Engine.IO rejects it with Session ID unknown. This is consistent with non-sticky routing and with node termination while clients remain pinned to the old node.
io cookie or JSESSIONID equivalent. Verify the affinity persists across the HTTP upgrade.Session ID unknown; keep sticky sessions for the handshake phase.One diagnostic detail that changes the recommendation: what Socket.IO major version are you running and what sticky mechanism does your load balancer provide, cookie-based affinity vs IP hash? Adapter initialization and sticky cookie names differ between v2 and v3/v4, and IP hash can break with NAT or mobile clients.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.