Home > Blog > Desenvolvimento Web
Desenvolvimento Web
JavaScript
Programação

Health Checks no Node.js: Guia Prático

Atualizado em: 5 de agosto de 2026

Rack de servidores processando fluxos de dados no Node.js

Load balancers, orquestradores e sistemas de monitoramento precisam saber se uma aplicação está viva e se pode receber tráfego. Os Health Checks no Node.js expõem endpoints simples que representam o estado do processo e de suas dependências.

Um único endpoint que consulta banco, cache, fila e serviços externos pode causar reinícios desnecessários durante uma falha temporária. Por outro lado, responder sempre 200 mantém uma instância quebrada no tráfego. A solução é separar liveness, readiness e startup, com limites claros e respostas rápidas.

Neste guia, você aprenderá a criar probes, verificar dependências, aplicar timeout, evitar efeito cascata, integrar graceful shutdown e definir informações seguras para observabilidade.

Liveness, readiness e startup

  • Liveness: indica se o processo está funcionando e não ficou irrecuperavelmente travado.
  • Readiness: indica se a instância está pronta para receber tráfego.
  • Startup: protege aplicações que precisam de mais tempo para inicializar.

Esses sinais possuem finalidades diferentes. Uma indisponibilidade do banco pode tornar a instância não pronta, mas não exige necessariamente reiniciar o processo.

A documentação do Kubernetes sobre liveness, readiness e startup probes apresenta o modelo. Para o servidor HTTP nativo, consulte a documentação do Node.js.

Veja também como criar uma API com Node.js e o que é Node.js.

Endpoint de liveness

app.get('/health/live', (req, res) => {
  res.status(200).json({
    status: 'alive'
  });
});

Liveness deve ser barata e não depender de rede externa. Se o endpoint consulta o banco, uma falha do banco pode fazer o orquestrador reiniciar todas as instâncias sem resolver a causa.

Estado de readiness

let ready = false;

async function start() {
  await database.connect();
  await cache.connect();
  ready = true;
}

app.get('/health/ready', (req, res) => {
  res.status(ready ? 200 : 503).json({
    status: ready ? 'ready' : 'not_ready'
  });
});

A flag representa inicialização e encerramento. Antes de fechar recursos durante deploy, mude para false. O guia de Graceful Shutdown no Node.js explica essa sequência.

Verificando banco de dados

async function checkDatabase() {
  const startedAt = performance.now();

  await database.query('SELECT 1');

  return {
    status: 'up',
    durationMs: performance.now() - startedAt
  };
}

Use uma consulta mínima e limite o tempo. Não execute migrações, relatórios ou leituras pesadas em cada probe.

Timeout por dependência

async function withTimeout(operation, milliseconds) {
  return Promise.race([
    operation(),
    new Promise((resolve, reject) => {
      setTimeout(() => {
        reject(new Error('health check timeout'));
      }, milliseconds);
    })
  ]);
}

Uma implementação melhor deve cancelar a operação subjacente com AbortSignal quando suportado. Veja AbortController no Node.js.

Readiness detalhada

app.get('/health/ready', async (req, res) => {
  const checks = await Promise.allSettled([
    withTimeout(checkDatabase, 1000),
    withTimeout(checkCache, 500)
  ]);

  const healthy = checks.every(item => item.status === 'fulfilled');

  res.status(healthy ? 200 : 503).json({
    status: healthy ? 'ready' : 'not_ready',
    checks: {
      database: checks[0].status,
      cache: checks[1].status
    }
  });
});

Não inclua URLs, credenciais, stack traces ou detalhes internos na resposta pública.

Dependências obrigatórias e opcionais

Nem toda dependência precisa retirar a instância do tráfego. Se cache está indisponível e a aplicação consegue usar o banco, readiness pode continuar positiva enquanto uma métrica e alerta indicam degradação.

const required = [databaseCheck];
const optional = [cacheCheck, analyticsCheck];

Documente qual recurso é essencial para cada função da aplicação.

Cacheando o resultado

Probes frequentes em várias instâncias podem sobrecarregar o banco. Execute verificações em intervalo controlado e sirva o último resultado:

let healthState = {
  ready: false,
  checkedAt: null
};

setInterval(async () => {
  healthState = await calculateHealth();
}, 5000).unref();

Considere a idade máxima. Um resultado antigo não deve permanecer saudável indefinidamente.

Startup probe

Aplicações que carregam modelos, aquecem cache ou executam migrações podem demorar. Uma startup probe evita que liveness reinicie o processo antes da conclusão. O endpoint pode usar a mesma flag de inicialização com política diferente na infraestrutura.

Event loop e liveness

Um endpoint não responde quando o event loop está completamente bloqueado, e o timeout da probe detecta isso. Para monitoramento interno, meça atraso do event loop e memória, mas não reinicie apenas por uma única oscilação.

const { monitorEventLoopDelay } = require('node:perf_hooks');

const histogram = monitorEventLoopDelay();
histogram.enable();

Tarefas de CPU devem ser tratadas com Worker Threads no Node.js.

Memória e disco

Memória alta não significa automaticamente que o processo está morto. Crie alertas e políticas graduais. Para serviços que gravam arquivos, espaço em disco pode ser um requisito de readiness, mas a consulta precisa ser barata.

Protegendo endpoints

Endpoints usados internamente podem ficar em porta administrativa ou rede restrita. Se forem públicos, retorne apenas estado geral. Não revele nomes de hosts, versões exatas, topologia ou mensagens de erro.

HTTP status

Use 200 quando saudável e 503 quando temporariamente indisponível para tráfego. A resposta deve ser pequena e possuir Cache-Control: no-store quando intermediários não devem armazená-la.

res.setHeader('cache-control', 'no-store');

Evite autenticação complexa na probe

Uma autenticação que depende do mesmo serviço externo pode impedir a infraestrutura de verificar a aplicação. Restrinja por rede, porta ou política do cluster. Se usar token, mantenha a validação local e simples.

Health checks e deploy

Durante deploy:

  1. a nova instância inicia não pronta;
  2. conecta dependências e aquece recursos;
  3. readiness passa a 200;
  4. a instância antiga muda readiness para 503;
  5. o tráfego é drenado;
  6. recursos são fechados.

Essa ordem evita enviar tráfego cedo demais ou interromper requisições existentes.

Observabilidade

Registre mudanças de estado, não cada chamada da probe. Crie métricas para duração, falhas por dependência, idade do último check e quantidade de transições. Combine com OpenTelemetry no Node.js.

Testando

Teste estado inicial, dependência saudável, timeout, falha opcional, shutdown e resultado antigo. Em integração, simule o banco indisponível e confirme que liveness continua viva enquanto readiness muda para 503.

Erros comuns

  • Usar a mesma lógica para liveness e readiness.
  • Consultar todas as dependências em cada liveness.
  • Não definir timeout.
  • Sobrecarregar o banco com probes.
  • Retornar detalhes sensíveis.
  • Continuar pronto durante shutdown.
  • Considerar cache opcional como falha total.
  • Armazenar resposta saudável por tempo indefinido.

Boas práticas

  • Mantenha liveness local e barata.
  • Use readiness para dependências essenciais.
  • Defina timeout curto por check.
  • Classifique dependências obrigatórias e opcionais.
  • Cacheie verificações com idade máxima.
  • Retorne respostas pequenas e seguras.
  • Mude readiness antes do shutdown.
  • Monitore transições de estado.
  • Teste falhas reais.
  • Ajuste intervalos à capacidade da infraestrutura.

Conclusão

Os Health Checks no Node.js permitem que a infraestrutura diferencie processo vivo de instância pronta. A separação entre liveness, readiness e startup evita reinícios em cascata e tráfego para serviços ainda indisponíveis.

Probes precisam ser rápidas, limitadas e seguras. Com dependências classificadas, timeouts e integração ao graceful shutdown, health checks se tornam sinais confiáveis da operação da aplicação.

Os 10 Melhores Cursos de Programação de 2026

Descubra os melhores cursos de programação. Aprenda a escolher o curso ideal para iniciar ou avançar na carreira de desenvolvedor

POSTS RELACIONADOS

Ver todos

Seta para a direita