module.exports = {
apps: [
{
name: 'api-service',
script: './dist/index.js',
instances: 'max',
exec_mode: 'cluster',
wait_ready: true,
listen_timeout: 8000,
kill_timeout: 4000,
max_memory_restart: '800M',
autorestart: true,
env_production: {
NODE_ENV: 'production',
PORT: 3000
},
time: true,
merge_logs: true
}
]
};Mulți încep cu un simplu pm2 start app.js și îl lasă așa pe VPS până crapă primul nod în producție. Am făcut și eu greșeala asta acum vreo 7 ani, când un deploy la ora 14:00 a aruncat 502-uri timp de 4 secunde pentru câteva sute de utilizatori activi.
Dacă vrei stabilitate reală, ai nevoie de un fișier ecosystem.config.js bine pus la punct, nu de comenzi rulate ad-hoc din terminal.
Cluster mode și graceful reload fără 502-uri
Node.js rulează single-threaded pe un singur core de CPU. Dacă serverul tău are 4 core-uri și rulezi instanța simplă (fork mode), lași 75% din resurse neutilizate.
Setarea exec_mode: 'cluster' împreună cu instances: 'max' (sau un număr fix dacă împarți serverul cu o bază de date) multiplică procesele automat. Dar cluster-ul singur nu garantează zero-downtime la deploy dacă faci pm2 restart.
Secretul pentru zero-downtime este pm2 reload combinat cu wait_ready: true și listen_timeout. În codul aplicației tale (Express/Fastify), după ce s-a conectat baza de date și serverul ascultă pe port, trebuie să trimiți semnalul:
app.listen(port, () => {
if (process.send) process.send('ready');
});
Astfel, PM2 nu oprește procesul vechi până când cel nou nu este 100% pregătit să preia trafic. La un API de plăți cu vreo 12k req/min, setarea asta ne-a redus erorile de conexiune tăiată la zero în timpul deploy-urilor automate.
Auto-restart la OOM: plasturele salvator de la ora 3 noaptea
Memory leak-urile se întâmplă și celor mai bune echipe, mai ales când depinzi de zeci de pachete npm pe care nu le-ai auditat linie cu linie. În loc să aștepți ca Linux OOM Killer să execute kill -9 pe tot procesul Node (luând eventual și alte servicii după el), setează max_memory_restart.
Dacă îi dai max_memory_restart: '800M', PM2 va reporni elegant worker-ul respectiv imediat ce atinge pragul, în timp ce ceilalți workeri din cluster continuă să preia request-uri.
Trade-off sincer: asta este o măsură de siguranță, nu o rezolvare. Dacă ai un leak urât, workerii se vor restarta în buclă la fiecare 10 minute și vei pierde contextul sesiunilor locale (dacă nu folosești Redis). Totuși, te scapă de pagere care sună în miezul nopții.
Log rotation: nu lăsa PM2 să-ți umple SSD-ul
Fiecare console.log din aplicație ajunge în ~/.pm2/logs/. Pe un server activ, fișierele astea ajung ușor la 20-30 GB în câteva luni dacă nu ești atent, moment în care baza de date refuză să mai scrie pe disc din lipsă de spațiu.
Poți seta merge_logs: true și timestamp-uri clare în configurare, dar cel mai sigur este să instalezi modulul oficial de rotire direct în mediul PM2:
pm2 install pm2-logrotate
pm2 set pm2-logrotate:max_size 50M
pm2 set pm2-logrotate:retain 7
Cum gestionați voi reload-urile în producție — mergeți pe PM2 în VPS clasic sau ați migrat totul în containere cu Kubernetes/Nomad?