eduardweb.
DevOps & VPSIntermediar#nodejs#devops#pm2#monitoring

Cum faci un healthcheck pe bune pentru PM2 (și ce ratează monitorizarea clasică)

De Cristian Barbu, 4 iul. 2026 · 16 vizualizări · 2 like-uri

Postat 4 iul. 2026
javascript
const express = require('express');
const app = express();
let dbLastCheck = 0;
let dbStatus = true;

app.get('/healthz', async (req, res) => {
  const now = Date.now();
  
  // Cache DB check for 10 seconds to avoid DDOSing our own DB
  if (now - dbLastCheck > 10000) {
    try {
      await db.ping(); // Înlocuiește cu clientul tău de DB (ex: pg, mongoose)
      dbStatus = true;
    } catch (err) {
      dbStatus = false;
    }
    dbLastCheck = now;
  }

  if (!dbStatus) {
    return res.status(503).send('Database connection error');
  }
  
  res.status(200).send('OK');
});

Am văzut prea multe proiecte în producție care se bazează orbește pe statusul verde din PM2, deși clienții primesc erori în browser. PM2 e excelent ca process manager, dar starea lui „online” înseamnă doar că procesul Node.js rulează ca proces în OS, nu și că este capabil să deservească trafic. În postarea asta vă arăt cum am rezolvat problema asta pe un proiect cu 14 microservicii unde ne loveam constant de conexiuni blocate.

De ce ne minte „pm2 status”

Cea mai mare capcană în care cad mulți developeri este să creadă că dacă pm2 list arată verde, totul e roz. Am pățit-o pe propria piele la un serviciu cu vreo 12.000 de useri activi. Procesul Node era blocat într-un loop infinit din cauza unui regex scris prost, CPU-ul era la 100%, event loop-ul era complet înghețat, dar PM2 raporta fericit statusul „online”.

PM2 monitorizează procesul din exterior. Nu are cum să știe dacă conexiunea ta la PostgreSQL a crăpat, dacă Redis-ul e plin și refuză comenzi sau dacă event loop-ul tău este atât de ocupat încât un request simplu durează 30 de secunde. Pentru sistemul de operare, procesul există și consumă resurse, deci PM2 îl lasă în pace.

Cum se face un healthcheck corect (și compromisul necesar)

Soluția este să expui un endpoint dedicat de /healthz direct din aplicație. Dar și aici apare un trade-off major. Dacă faci interogări grele în baza de date la fiecare apel de healthcheck, riști să îți blochezi singur baza de date atunci când load balancer-ul verifică starea aplicației la fiecare 2 secunde.

La proiectul menționat, aveam momente când conexiunea la baza de date pica preț de 5 secunde din cauza unor backup-uri automate. Fără cache pe healthcheck, toate cele 14 servicii raportau „unhealthy” simultan, load balancer-ul le tăia pe toate din rotație, iar PM2 începea să le restarteze în buclă — un adevărat dezastru de tip cascading failure. Am pierdut o noapte întreagă curățând log-urile.

Am rezolvat asta printr-un compromis simplu: cache în memorie de 10 secunde pentru verificările grele. Verificăm dacă baza de date răspunde, dar salvăm rezultatul. Dacă load balancer-ul ne întreabă mai des, îi dăm răspunsul din cache. E suficient de rapid și nu omorâm baza de date.

Un alt aspect critic este timeout-ul pe request. Dacă event loop-ul este blocat, request-ul către /healthz va expira. Load balancer-ul (sau un script extern) trebuie să aibă un timeout agresiv (de exemplu, 2-3 secunde). Dacă nu primește răspuns în acest interval, consideră procesul ca fiind mort și îl scoate din rotație.

Cum legăm asta de PM2 în mod real

Dacă rulezi pe un VPS clasic fără orchestratoare mari, poți folosi un script simplu de cron care rulează local la fiecare minut. Scriptul face un curl pe portul aplicației și, dacă primește altceva decât HTTP 200 sau dacă request-ul dă timeout, rulează un pm2 reload <app_name>.

În felul ăsta, dacă aplicația ta e blocată la nivel de event loop, scriptul o va prinde și o va reporni curat, fără să aștepți să se umple memoria sau să primești alerte de la clienți.

Voi cum gestionați treaba asta în producție? Vă bazați doar pe restart-ul automat la memory limit din PM2 sau aveți endpoint-uri dedicate de health check monitorizate extern?

Răspunsuri 0

Se încarcă răspunsurile…

Loghează-te pentru a răspunde

Doar membrii comunității pot lăsa comentarii.