Sticky Sessions and WebSockets
Keep a user's requests on the same pod when your application runs several replicas, and what to check when WebSocket connections drop.
This page explains how to keep a user's requests on the same pod when your
application runs more than one replica, and what to check first for WebSocket or
real-time connections that drop.
When you need this
By default, the platform ingress (Traefik) spreads requests across all healthy
pods of a Component. That is right for stateless applications. You need sticky
sessions, also called session affinity, when a pod holds per-user state in its
own memory, for example:
- in-memory login sessions or shopping carts
- real-time hubs such as SignalR or Socket.IO, where a fallback transport such
as long polling sends several HTTP requests that must reach the same pod - a multi-step flow that stores progress on the pod that started it
Typical symptoms without it: users are logged out at random, or a real-time
client reports an intermittent 404 Not Found or an unknown connection ID. These
symptoms appear only when the Component runs two or more replicas.
Consider a shared session store first
Sticky sessions hide the problem rather than remove it. Before requesting them,
check whether your application can keep its session state outside the pod:
| Sticky sessions | Shared session store | |
|---|---|---|
| Pod restart, deployment or scale-in | Users on that pod lose their session | Sessions survive |
| Load across pods | Can become uneven, since long-lived users stay put | Even |
| Autoscaling | New pods only receive new users | New pods share the load at once |
| Change needed | Platform configuration | Application configuration |
Most frameworks support a Redis-backed session store, and real-time libraries
such as SignalR and Socket.IO offer a Redis backplane or adapter so that any pod
can deliver a message to any connected client. The platform can provide a
managed Redis for this — see Data Services.
Even with sticky sessions, a user moves to another pod whenever their pod is
replaced, which happens on every deployment and during node maintenance. Your
application should tolerate that, for example by reconnecting cleanly.
Requesting cookie-based sticky sessions
The Component configuration in SVIEW does not expose a sticky-session setting,
so stickiness is set up by CTO2B on the ingress. Raise a request in your
dedicated Slack channel and we confirm whether it can be enabled for that
Component. Include:
- the Environment and the Component name
- the hostname and path that need stickiness
- a cookie name, if you need a specific one; otherwise the platform chooses one
- whether the cookie must be
SecureandHttpOnly, and anySameSite
requirement, for example if the application is embedded in another site
Stickiness works with a cookie that the ingress sets on the first response. The
client must send that cookie back on later requests, which browsers do
automatically. Non-browser clients, such as mobile apps or server-to-server
callers, must store and resend it themselves.
Affinity based on the client IP address, or on the value of an arbitrary request
header, is not offered. Behind a shared load balancer the client IP is not a
reliable key, and Traefik does not balance by header value. If you need routing
by a header, a shared session store is the supported way to achieve it.
WebSocket connections
WebSockets work through the platform ingress with no extra configuration. A
WebSocket stays on the pod it first connected to for its whole lifetime, so a
pure WebSocket connection does not need sticky sessions. You need them only when
the client also uses HTTP requests that must reach the same pod, such as the
negotiate step or a long-polling fallback.
If WebSocket connections close after a period of silence:
- Enable the keep-alive or ping option of your WebSocket library, so that the
connection is never idle for long. An interval of 15 to 30 seconds is a
common choice. - Make sure the client reconnects automatically. Connections also close when a
pod is replaced. - If connections still close at a consistent interval, raise a request with
that interval, the hostname, and the time of a failed connection so it can be
matched against the ingress logs.
Related articles
Updated 26 days ago