E duminică seară și primești primele tichete de la suport: 'Mă deloghează întruna'. Te uiți rapid în cod, vezi maxAge: 30 * 24 * 60 * 60 * 1000. Totul pare brici, o lună întreagă de liniște. Verifici în browser, cookie-ul de sesiune are data de expirare corectă, undeva hăt în viitor. Și totuși, după 5 minute de inactivitate, userul e trimis direct la /login. E genul de bug care te face să te îndoiești de realitate și de tot ce ai învățat în zece ani de dev.
Am avut cazul ăsta acum vreo doi ani la un proiect de e-commerce destul de măricel, cu vreo 12k useri activi zilnic. Am pierdut cam 15% din conversii într-o singură dimineață până ne-am prins unde era buba. Problema e că mulți dintre noi tratăm cookie-ul și sesiunea ca pe același lucru, dar ele trăiesc în lumi total diferite. Cookie-ul e doar un ID, o etichetă lipită pe fruntea browserului. Dacă serverul 'uită' ce înseamnă ID-ul ăla, poți să ai tu cookie valabil și o sută de ani, că tot afară ajungi.
Unde e buba pe server?
Prima chestie pe care trebuie să o verifici e unde anume ții sesiunile. Dacă folosești store-ul default din Node.js (MemoryStore) sau ceva similar în PHP/Python, ai dat de dracu' la prima replicare a aplicației sau la primul restart. La proiectul de care ziceam, aveam 3 instanțe în Docker în spatele unui Load Balancer. Dacă userul făcea primul request pe instanța A și al doilea pe instanța B, B habar n-avea cine e omul ăla pentru că sesiunea stătea doar în memoria RAM a primei instanțe.
Apoi, verifică setările de 'Idle Timeout' din framework-ul tău. Multe librării de sesiune au un mecanism de garbage collection care șterge sesiunile inactive după un anumit timp, indiferent de cât de mare e maxAge-ul setat pe cookie. Am economisit vreo 20GB de RAM la un moment dat pe un server de Redis doar optimizând TTL-ul (Time To Live), dar dacă îl pui prea mic (cum era setarea default de 300 de secunde pe care am găsit-o eu atunci), îi omori pe useri.
Infrastructura și 'Silent Killers'
Dacă ai un load balancer (NGINX, AWS ALB sau Cloudflare) care nu are 'sticky sessions' activat și nu ai un store extern (Redis/DB), ești la mâna norocului. Fără stickiness, request-urile sar de la un server la altul ca mingea de ping-pong. E obligatoriu să ai un store centralizat dacă vrei să scalezi peste un singur nod.
Un alt vinovat silențios e modul în care serverul de Redis (dacă folosești așa ceva) gestionează memoria. Dacă Redis-ul e plin și ai politica allkeys-lru, s-ar putea să înceapă să dea afară chei de sesiune ca să facă loc la altele noi, chiar dacă ele n-au expirat încă 'teoretic'. E un trade-off sincer: Redis e rapid de rupe, dar dacă nu-i dai destul RAM, începe să facă curățenie de capul lui.
Cum diagnostichezi rapid fără să înnebunești?
Nu te uita doar în DevTools la tab-ul Application. Deschide tab-ul Network și verifică header-ul Set-Cookie la fiecare request. Dacă vezi că serverul trimite un ID nou de sesiune deși tu ești logat, e clar: serverul a pierdut urma vechii sesiuni și încearcă să 'repare' situația trântindu-ți una nouă, goală.
Verifică și logurile de la orchestrator (Kubernetes sau PM2). Dacă aplicația ta își dă restart din 5 în 5 minute din cauza unui memory leak mic, sesiunile in-memory dispar odată cu procesul. Am pățit asta la un serviciu de notificări unde un buffer nedeclarat corect umplea RAM-ul și declanșa un OOM (Out Of Memory) kill periodic.
Voi cum gestionați persistența sesiunilor? Mergeți pe Redis direct sau preferați să le aruncați în baza de date principală (Postgres/Mongo) ca să fiți siguri că nu dispar la restart?