module.exports = {
apps: [{
name: 'api-service',
script: './dist/server.js',
instances: 'max',
exec_mode: 'cluster',
max_memory_restart: '800M',
listen_timeout: 10000,
kill_timeout: 5000,
wait_ready: true,
env_production: {
NODE_ENV: 'production',
PORT: 3000
}
}]
};Am văzut prea multe VPS-uri prăbușite pentru că aplicația rulat cu pm2 start server.js direct din CLI. Dacă nu folosești un fișier ecosystem.config.js bine structurat, pierzi jumătate din beneficiile pe care ți le oferă PM2 pe Node.js. Adun aici setările de la care plec în orice proiect de producție ca să evite picajele stupide când se umple discul sau crapă memoria.
Cluster mode și capcana de care m-am lovit
Node.js e single-threaded, asta știm toți. Când pui exec_mode: 'cluster' și instances: 'max' (sau -1 dacă vrei să lași un nucleu liber pentru sistem), PM2 multiplică procesul pe toate nucleele CPU disponibile. La un proiect cu un API ce procesa în jur de 8k request-uri pe minut, schimbarea asta simplă ne-a dus latența medie de la 450ms la sub 80ms fără niciun alt refactoring în cod.
Dar vine cu un trade-off direct: state-ul în memorie devine inutilizable. Dacă salvezi sesiuni în memorie prin express-session sau ții un cache local într-un obiect global, o să ai bug-uri bizare unde un user e autentificat pe worker-ul 1, dar la următorul click ajunge pe worker-ul 2 și e deconectat. Treci neapărat sesiunile și cache-ul în Redis înainte să treci aplicația în cluster mode.
Graceful reload: Zero downtime real
Mulți folosesc pm2 restart app, care oprește brutal toate procesele și apoi le repornește. Rezultatul? Câteva secunde în care clienții tăi primesc erori de tip 502 Bad Gateway. Varianta corectă pentru deploy este pm2 reload ecosystem.config.js --env production.
Ca reload-ul să fie într-adevăr graceful, ai nevoie de listen_timeout și kill_timeout configurate corect. În plus, în aplicația ta de Node.js trebuie să asculți de semnalul SIGINT. Când PM2 trimite semnalul de oprire, worker-ul vechi nu mai acceptă conexiuni noi, își termină treaba cu request-urile aflate deja în derulare și abia apoi face exit curat.
Ce faci cu memoria scăpată sub control și log-urile?
Dacă lași PM2 să scrie log-uri fără o strategie, în 2-3 luni te trezești cu discul plin 100% și baza de date blocată. Am pățit chestia asta prin 2018 pe un server de staging și de atunci e prima chestie pe care o securizez. Instalează modulul pm2-logrotate pe server (pm2 install pm2-logrotate) pentru că PM2 nativ nu știe să taie fișierele de log la o anumită dimensiune.
La partea de memorie, opțiunea max_memory_restart: '800M' este colacul tău de salvare. Node.js mai scapă memorie, mai ales când lucrezi cu procesare de imagini, PDF-uri sau stream-uri mari. Dacă un worker depășește limita setată, PM2 îi dă restart automat fără să afecteze ceilalți workeri din cluster.
Voi ce alte opțiuni aveți definite ca standard în fișierul de PM2 când trimiteți un API în producție?