const session = require('express-session');
const RedisStore = require('connect-redis').default;
const { createClient } = require('redis');
let redisClient = createClient({ url: 'redis://localhost:6379' });
redisClient.connect().catch(console.error);
app.use(session({
store: new RedisStore({ client: redisClient, ttl: 2592000 }), // 30 zile în secunde
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
rolling: true, // Resetează expirarea la fiecare request activ
cookie: {
secure: true,
httpOnly: true,
maxAge: 30 * 24 * 60 * 60 * 1000 // 30 zile în milisecunde
}
}));Salutare tuturor. Am decis să scriu despre asta pentru că m-am lovit de problemă acum ceva timp la un proiect cu peste 12k useri activi și am pierdut câteva ore bune înjurând ecranele. Pe hârtie, totul părea perfect: cookie-ul de sesiune avea maxAge setat pe 30 de zile, securizat, HTTP-only, tot tacâmul. Cu toate astea, suportul era inundat de tichete de la oameni care ziceau că sunt scoși din cont din 5 în 5 minute.
Dacă ești în situația asta, problema nu e la client. Browserul trimite cookie-ul cuminte, dar serverul tău suferă de amnezie. Hai să-ți zic unde să sapi.
1. Capcana MemoryStore în producție (cazul Node.js / Express)
Dacă folosești Express cu express-session și nu ai configurat un store extern, folosești implicit MemoryStore. Este cel mai mare anti-pattern pentru producție.
De ce? Pentru că memoria RAM a procesului se curăță la fiecare restart. Dacă ai aplicația pusă pe PM2 în mod cluster, sau folosești containere Docker pe AWS/DigitalOcean care fac auto-scale, fiecare request al userului poate ajunge la un proces diferit. Procesul A știe cine e userul, dar procesul B, pornit acum 2 minute, nu are nicio idee. Rezultatul? Userul primește instant redirect către login.
2. Serverul șterge sesiunile prea repede (PHP / Redis TTL)
Dacă folosești PHP, te lovești de session.gc_maxlifetime din php.ini. Chiar dacă trimiți un cookie valabil o lună, PHP are un mecanism de "garbage collection" care șterge fișierele de sesiune de pe disc după 24 de minute (valoarea implicită).
La fel se întâmplă și dacă folosești Redis pentru stocarea sesiunilor, dar ai uitat să configurezi TTL-ul (Time To Live) al cheilor din baza de date să se potrivească cu durata cookie-ului. Dacă Redis șterge cheia după 15 minute, cookie-ul ăla de 30 de zile din browser devine doar o cheie inutilă către o cameră goală.
3. Lipsa opțiunii de "Sliding Expiration"
Unele framework-uri dezactivează implicit actualizarea cookie-ului la fiecare request. Dacă userul tău stă activ pe site timp de 30 de minute, dar sesiunea pe server a fost setată fix pe 30 de minute fără "rolling", el va fi delogat în minutul 31, chiar dacă a dat click-uri în mod constant.
Cum am rezolvat eu problema
Am mutat stocarea sesiunilor din memoria locală în Redis și am activat opțiunea rolling: true (în Express). Asta înseamnă că la fiecare request activ al userului, durata de viață a cookie-ului și a sesiunii se resetează, oferindu-i încă 30 de zile de valabilitate.
Trade-off-ul aici e simplu: Redis adaugă un mic delay de rețea la fiecare request (câteva milisecunde) și costă ceva mai mult la infrastructură decât stocarea pe disc sau în memoria locală. Însă pentru experiența userului și stabilitatea aplicației, merită fiecare cent. Am redus bounce rate-ul pe checkout cu 15% doar din fix-ul ăsta.
Voi cum gestionați sesiunile persistente? Mergeți pe JWT-uri în localStorage sau rămâneți fideli sesiunilor clasice pe server?