module.exports = {
apps: [{
name: 'api-prod',
script: './dist/server.js',
instances: 'max',
exec_mode: 'cluster',
wait_ready: true,
listen_timeout: 5000,
kill_timeout: 3000,
max_memory_restart: '800M',
env: {
NODE_ENV: 'production',
PORT: 3000
}
}]
};Salutare! Văd destul de des oameni care rulează aplicații Node.js în producție doar cu un simplu pm2 start app.js. E în regulă pentru un pet project, dar când ai trafic real și vrei zero-downtime, ai nevoie de un ecosystem.config.js bine pus la punct. Am pățit-o la un proiect cu vreo 12k useri activi, unde serverul crapa random din cauza unui memory leak ascuns într-o librărie externă. Configurarea corectă a PM2 ne-a salvat nopțile și reputația până am reușit să facem debug pe bune.
Hai să vedem cum se configurează PM2 ca un profesionist și ce decizii de design trebuie să iei.
Configurația de bază de la care plecăm
În loc să dai argumente lungi în terminal, pui totul într-un fișier de configurare JS. E mult mai simplu de versionat în Git și de integrat în pipeline-ul de CI/CD. Codul din secțiunea dedicată arată exact structura pe care o folosesc eu pe majoritatea serverelor VPS.
Cluster mode și de ce avem nevoie de Graceful Reload
Opțiunea instances: 'max' va porni câte o instanță a aplicației pentru fiecare core CPU disponibil. Dacă ai un server cu 4 core-uri, vei avea 4 procese Node care împart aceeași mână de porturi prin load balancer-ul intern din PM2. Performanța crește spectaculos fără să schimbi o linie de cod.
Adevărata magie apare la deployment. În loc de pm2 restart all, care omoară instant toate procesele și dă erori de conexiune (502 Bad Gateway) utilizatorilor activi, vei folosi pm2 reload all.
Acest "graceful reload" omoară procesele pe rând. În timp ce instanța 1 repornește cu noul cod, instanțele 2, 3 și 4 preiau tot traficul. Ca să funcționeze perfect, codul tău trebuie să asculte de semnalul SIGINT trimis de PM2 și să închidă conexiunile la baza de date înainte de a opri procesul.
Trade-off sincer: Cluster mode funcționează de minune doar dacă aplicația ta este complet stateless. Dacă ții sesiuni în memoria procesului (și nu în Redis/bază de date) sau dacă ai cron-uri interne scrise direct în Express, cluster mode o să le ruleze pe fiecare instanță în paralel. Te poți trezi că trimiți același newsletter de 4 ori la rând. Pentru aplicații stateful, rămâi pe fork mode.
Auto-restart la OOM (Out of Memory) și Log-uri care îți umplu discul
În config am setat max_memory_restart: '800M'. Node.js are momente când "uită" să facă garbage collection rapid sau, pur și simplu, codul tău are un memory leak mic de care nu ai timp să te ocupi azi. Decât să lași procesul să mănânce toată memoria RAM și să blocheze întreg serverul (OOM Killer de la Linux va omorî procese random), mai bine lași PM2 să îi dea restart când trece de pragul de 800MB. Cu cluster mode activ, userii nici nu vor observa repornirea.
O altă problemă clasică: log-urile scrise în out.log și err.log cresc până umplu discul. Am pățit pe un VPS de 20GB să mi se oprească baza de date din lipsă de spațiu pentru că PM2 strânsese 12GB de log-uri necompresate.
Soluția nu se scrie în ecosystem.config.js, ci se instalează ca modul global pe server:
pm2 install pm2-logrotate
După instalare, configurează-l să ruleze zilnic și să păstreze o dimensiune decentă:
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 10
Asta va păstra doar ultimele 10 fișiere de log, de maximum 10MB fiecare, comprimate.
Voi cum gestionați procesele de Node în producție? Mergeți în continuare pe PM2 clasic sau ați trecut complet pe Docker/Kubernetes chiar și pentru proiectele de dimensiune medie?