design decision
Where sessions live
The monolith split leaves session state homeless: today it rides the app server's memory and dies with it. The choice has narrowed to three operating models, with Redis and a short signed-cookie fallback recommended.
Constraints
- Logout must revoke immediately — support runs "log out all devices" during account-takeover response.
-
Session writes happen on every request (
rolling expiry ), so the store sees full request volume. - The team already operates Redis for rate limiting; nobody runs Dynamo-style infrastructure today.
Settled: the session id travels in a host-only Lax cookie
How the session id travels was decided before this page and the client change is merged, so it reads as one line — open it if you want the alternatives.
The payments precedent is useful — and not equivalent
Payments settled a similar question in March. Its answer does not travel cleanly: payments had a tenth of our write volume and nothing that had to survive the store going down.
- Writes
- a tenth of ours
- Store down
- queue and retry
A payment is seconds long, so a Redis blip is a spinner and a retry, and nothing about their answer had to outlive the store.
- Writes
- every request
- Store down
- readers stay signed in
Rolling expiry writes on every request, and an outage must not sign the fleet out — the constraint their page never had to argue.
Where should a session live?
- Revoke
- build a denylist
- Outage
- unaffected
- New ops
- none, at first
Sessions become signed tokens; no store at all. Revocation requires a denylist, which quietly reintroduces the store — with the hard parts (replication, expiry) still attached, and the account-takeover response waiting on them.
With nothing stored there is nothing to list, so the support console loses its per-device Revoke and "log out all devices" waits on the token's own expiry.
- Revoke
- delete the key
- Outage
- reads ride the cookie
- New ops
- what we already do
Sessions in the Redis we already run, keyed by an opaque id; a short-lived signed cookie covers Redis outages for reads, so a blip doesn't log everyone out. Revocation is a delete — which is the shape support's "log out all devices" needs. My take: this preserves revocation without making Redis an outage.
- Revoke
- delete the row
- Outage
- shares the database's fate
- New ops
- vacuum pressure
One table, no new moving parts. Every request writes a row (rolling expiry), so at our volume that's the primary's headroom spent on expiry bookkeeping — and a session outage becomes a database outage.