module.exports = {
apps: [
{
name: 'api-prod',
script: './dist/server.js',
instances: 'max',
exec_mode: 'cluster',
autorestart: true,
max_memory_restart: '450M',
kill_timeout: 5000,
wait_ready: true,
listen_timeout: 4000,
env: {
NODE_ENV: 'production',
PORT: 3000
}
}
]
};Dacă rulezi Node.js în producție cu un simplu pm2 start app.js, ratezi exact motivele pentru care PM2 încă e relevant în era containerelor. Am avut acum doi ani un incident la un API cu ~12k request-uri pe minut unde un memory leak stupid la generarea de PDF-uri umplea RAM-ul și bloca tot procesul până dădea kernel-ul OOM killer.
Soluția curată nu e să dai restart manual din SSH noaptea, ci să lași un ecosystem.config.js bine pus la punct să gestioneze ciclul de viață al proceselor.
Cluster mode și graceful reload
Node.js e single-threaded pe event loop, deci pe un VPS cu 8 vCPU-uri un proces simplu folosește un singur core. Prin exec_mode: 'cluster' și instances: 'max' (sau un număr fix dacă vrei să lași resurse libere pentru baze de date sau Redis), PM2 instanțiază mai mulți workeri prin modulul intern cluster.
Problema clasică la deploy apare când dai pm2 restart. Comanda asta oprește brutal toate procesele și le repornește, lăsând clienții cu conexiuni tăiate timp de 2-3 secunde. Pentru zero-downtime deployment, ai nevoie de pm2 reload ecosystem.config.js.
Ca reload-ul să fie cu adevărat graceful, aplicația ta trebuie să asculte de semnalul SIGINT și să elibereze resursele, iar în config setezi kill_timeout (timpul de așteptare înainte de SIGKILL) și listen_timeout.
Protecție la Memory Leaks (OOM restart)
Oricât am vrea să credem că scriem cod fără scăpări de memorie, bibliotecile terțe sau parsările masive de date pot produce leak-uri insidioase. În loc să aștepți ca Linux-ul să omoare procesul sau să blocheze mașina virtuală din lipsă de swap, setezi max_memory_restart: '500M'.
Când procesul depășește pragul, PM2 îl repornește automat în fundal. Dacă ești în cluster mode, celelalte instanțe preiau traficul fără ca vreun utilizator să observe că un worker a fost reciclat.
Trade-off-uri de reținut
Cluster mode funcționează impecabil pentru API-uri stateless. Dacă ții sesiuni în memoria procesului local în loc de Redis, cluster-ul îți va sparge logica de auth deoarece un user va lovi instanțe diferite de la un request la altul.
La fel, dacă ai job-uri de tip cron (node-cron) rulate direct în aplicație, pe instances: 4 cron-ul tău se va executa de 4 ori simultan. Pentru cron-uri recomand un worker separat definit ca o a doua aplicație în același ecosystem.config.js, rulat cu instances: 1.
Pentru loguri, nu lăsa PM2 să scrie la infinit în ~/.pm2/logs. Instalează modulul de rotație direct cu pm2 install pm2-logrotate, careArchivează și comprimă fișierele zilnic sau la depășirea unei limite de dimensiune (ex: 50MB).
Voi mai folosiți PM2 direct pe mașini virtuale/bare-metal sau ați migrat complet spre orchestrare cu Docker și Kubernetes?