# Verifică rapid TTL-ul real al sesiunii în Redis
redis-cli KEYS "sess:*" | head -n 5
# Ia un ID de sesiune activă și verifică secundele rămase:
redis-cli TTL "sess:d3b07384d113edec49eaa6238ad5ff00"
# Verifică dacă Redis dă afară chei din lipsă de RAM
redis-cli INFO stats | grep evicted_keysAi inspectat request-ul în DevTools, Set-Cookie are Max-Age: 2592000 (fix 30 de zile), SameSite e pus pe Lax, Secure e bifat, și totuși utilizatorii se trezesc delogați la prima cafea. Am tras două zile de scenariul ăsta la o platformă B2B cu vreo 12k utilizatori activi, până când am realizat că ne uitam cu toții în locul greșit: la client, în loc de starea din spate.
Când cookie-ul rezistă dar sesiunea moare, problema nu e HTTP-ul. E stocarea sau infrastructura de rutare.
1. TTL-ul din Redis nu bate cu TTL-ul din cookie
Cea mai frecventă greșeală: setezi maxAge pe cookie în framework (de exemplu Express, Laravel sau Django), dar magazinul de sesiuni are propria viață. Degeaba are biletul tău valabilitate 30 de zile dacă cinema-ul se închide după 5 minute.
Dacă folosești Redis sau Memcached, verifică TTL-ul efectiv pe cheia de sesiune direct din consolă. Am văzut configurări unde librăria de sesiune făcea fallback pe valoarea default a serverului (de multe ori 300 de secunde) dacă proprietatea ttl din store nu era specificată explicit, indiferent de ce trimiteai în antetul HTTP.
2. Evicția din Redis (lipsa de memorie)
La proiectul menționat mai devreme, asta a fost buba reală. Redis-ul rula pe o instanță mică de 512MB RAM, partajată între cache-ul de produse și sesiuni. Un cron job a început să bage mii de query-uri grele în cache.
Redis a atins maxmemory, iar politica configurată era allkeys-lru. Ce a făcut Redis? A început să șteargă cele mai vechi chei pentru a face loc noilor intrări din cache. Ghici ce a zburat mai întâi: sesiunile utilizatorilor inactivi de câteva minute.
Trade-off-ul aici e clar: nu ține niciodată sesiunile critice în același Redis cu cache-ul volatil fără o politică strictă de volatile-ttl sau, ideal, o instanță complet separată.
3. Infrastructură multi-node fără Sticky Sessions sau Centralized Store
Dacă ai două containere sau două instanțe EC2 în spatele unui Load Balancer și n-ai setat sesiuni distribuite, se întâmplă clasica pasare de la un nod la altul. Userul dă login pe Nodul A (unde se creează sesiunea locală în memorie), următorul click ajunge pe Nodul B via round-robin, iar Nodul B zice politicos: „Nu te cunosc, 401”. Pare că pierzi sesiunea după câteva minute, dar de fapt o pierzi la primul request trimis pe un nod diferit.
4. Fingerprinting agresiv pe IP (rețele mobile)
Mulți dezvoltatori încearcă să fie riguroși pe securitate și leagă sesiunea de adresa IP a clientului (hash(IP + User-Agent)). Pe desktop merge decent. Pe mobil, e un coșmar.
Când cineva navighează de pe telefon și telefonul face saltul de la Wi-Fi la 4G/5G, IP-ul public se schimbă instant. Dacă backend-ul invalidează sesiunea la modificarea IP-ului, tocmai ai creat un bug fantomă care afectează doar utilizatorii de pe mobil la fix câteva minute după ce au ieșit pe ușă.
Soluția cinstită: leagă sesiunea strict de un ID criptografic generat corect și eventual verifică familia de ASN sau User-Agent-ul, nu IP-ul exact.
Voi ce ciudățenii ați mai prins care omorau sesiuni pe silențios?