Storing sessions as Hashes vs JSON strings, sliding expiry with EXPIRE on each request, session invalidation and logout, multi-device session tracking, and the consistency trade-offs when reading sessions from replicas.
P-9 — Session Management Patterns
Who this module is for: You store user sessions in Redis — or are planning to — and want to implement them correctly. This covers session structure (Hash vs JSON string), sliding expiry, concurrent device management, and the read-from-replica consistency trap that silently logs users out.
Why Redis for Sessions
HTTP is stateless. Sessions provide continuity: a session token in a cookie maps to server-side state (user ID, permissions, preferences). The session store must be:
- Fast — checked on every request
- Shared — accessible from every application server instance
- Expirable — sessions must auto-expire when idle or after a fixed duration
Redis satisfies all three. A 1ms session lookup is imperceptible. Every application server connects to the same Redis instance. TTL handles expiry automatically.
The alternative — database-backed sessions (PostgreSQL, MySQL) — works but adds a database query to every request, and relational databases are optimized for complex queries, not millions of simple ID lookups.
Session Structure: Hash vs JSON String
Option A: JSON String
SET session:{token} '{"userId":1001,"email":"j@example.com","role":"engineer","permissions":["read","write"]}' EX 3600
Simple. One key, one value. But updating a single field requires:
GET session:{token}→ deserialize JSON- Modify the field in application memory
SET session:{token} {updated JSON}→ re-serialize and overwrite
Under concurrent requests (two requests updating different session fields simultaneously), one overwrites the other's changes. Race condition.
Option B: Redis Hash
Individual field updates are atomic:
Multiple fields can be updated without touching others. No race condition for independent field updates.
The trade-off: Hashes require one more key + the field name overhead. For sessions with 5–10 fields, the overhead is minimal. For sessions storing complex nested objects, you may need to serialize sub-objects as JSON strings within Hash fields.
Recommendation: Use a Hash for session storage. It enables atomic per-field updates and makes session data self-describing (HGETALL returns field names, not just a JSON blob).
Session Expiry: Idle Timeout vs Absolute Timeout
Idle Timeout (Sliding Expiry)
The session expires if unused for N minutes. Activity resets the timer.
Call touchSession on every authenticated request. If it returns false, the session expired and the user should be logged out.
Absolute Timeout
The session expires at a fixed time after creation, regardless of activity. Implement by storing the absolute expiry timestamp in the session Hash and checking it on every access:
Sign in to keep reading
The rest of this module is free — sign in with Google to unlock it and track your progress.
Sign in & RegisterDiscussion
0Join the discussion