O Ciclo de Vida do Processo Node.js
Executar um serviço Node.js em produção não é a mesma habilidade que escrevê-lo.
Busque em todas as páginas da documentação
Executar um serviço Node.js em produção não é a mesma habilidade que escrevê-lo.
Um script que funciona perfeitamente sob node app.js em um laptop ainda pode falhar na implantação de um orquestrador, descartar requisições em andamento em cada deploy, ou ficar travado para sempre no desligamento - porque nenhuma dessas falhas reside na lógica da aplicação. Elas vivem no ciclo de vida do processo: a sequência pela qual um processo Node passa desde o momento em que um supervisor o inicia até o momento em que ele sai, e os sinais e verificações dos quais essa sequência depende.
Esta página é o modelo mental por trás de todo o resto nesta seção. Noções Básicas de Operações de Runtime explora exemplos práticos de endpoints de integridade e manipuladores de desligamento; Desligamento Gracioso, Implantações de Tempo Zero de Inatividade e PM2 & systemd aprofundam cada estágio. Aqui, o objetivo é a forma do ciclo de vida completo e por que um orquestrador, e não o código da sua aplicação, é quem o conduz.
SIGTERM ou um supervisor com um período de graça muito curto quebra o contrato de qualquer um dos lados.Um processo Node é, em nível de sistema operacional, nada de especial - é um processo do SO, com um PID, ao qual o SO pode enviar sinais e que eventualmente sai com um código de status.
O que torna "runtime ops" uma disciplina própria é que, em produção, este processo nunca está rodando sozinho. Ele fica dentro de um supervisor - systemd, PM2, um plano de controle de um cluster Kubernetes, uma plataforma serverless - cujo único trabalho é decidir quando iniciá-lo, quando rotear tráfego para ele, quando pará-lo e quando reiniciá-lo se ele morrer inesperadamente.
Essa relação de supervisor reformula o que significa "parar um servidor". Em um laptop, parar significa Ctrl+C e o processo desaparece. Em produção, parar é uma negociação: o supervisor pede ao processo para parar, e o processo recebe uma janela de tempo para terminar o que está fazendo antes que o supervisor force a questão.
Uma analogia útil é uma troca de turno em um balcão de restaurante. O servidor que sai não sai no meio de um pedido assim que seu turno termina - ele para de aceitar novos pedidos, termina os tickets que já tem em mãos e só então bate o ponto. O gerente (o supervisor) define um prazo para essa passagem de bastão; se o servidor ainda estiver lá quando o prazo expirar, o gerente intervém e fecha o caixa de qualquer maneira. A sequência de desligamento de um processo Node segue a mesma forma: parar de aceitar novo trabalho, terminar o trabalho em andamento, e então sair - tudo dentro de um período de graça que outra pessoa controla.
O ciclo de vida tem cinco estágios, e cada um é acionado por um sinal ou verificação diferente:
start ──▶ ready ──▶ serving ──▶ draining ──▶ exit
│ │ │ │ │
process ready- normal SIGTERM process
inicia probe request recebido, code 0
passa atendimento parar novo (ou SIGKILL
trabalho, após período
terminar de graça)
trabalho em
andamento
Start é o boot do processo - carregamento de módulos, análise de configuração, abertura de pools de banco de dados. Nada deve servir tráfego ainda, pois as dependências podem não estar conectadas.
Ready é o ponto em que uma sonda de prontidão (um endpoint HTTP como /ready, ou uma verificação equivalente) começa a retornar sucesso. Isso é uma pergunta diferente de liveness: liveness pergunta "o processo ainda está rodando e não está travado?", enquanto readiness pergunta "o tráfego deve ser roteado para ele agora?". Um processo pode estar vivo, mas não pronto - por exemplo, ainda abrindo um pool de conexões de banco de dados - e um orquestrador que confunde os dois roteará requisições para um processo que não está preparado para lidar com elas.
Serving é o manuseio de requisições em estado estável, o estágio em que um processo passa a maior parte de sua vida.
Draining começa no momento em que o processo recebe SIGTERM - o sinal de "por favor, pare" em nível de SO que todo supervisor envia antes de uma parada, redução de escala ou deploy. Este é o estágio onde a maioria dos bugs de runtime-ops vive, pois exige que o processo faça várias coisas em ordem: alternar a sonda de prontidão para falha (para que o balanceador de carga pare de enviar novas requisições), parar de aceitar novas conexões, deixar as requisições em andamento terminarem, fechar recursos como pools de banco de dados de forma limpa, e só então sair. Desligamento Gracioso cobre essa sequência em detalhes.
let ready = true;
process.on('SIGTERM', async () => {
ready = false; // sonda de prontidão agora falha - LB para de rotear aqui
server.close(async () => { // parar de aceitar novas conexões; esperar pelas em andamento
await dbPool.end(); // fechar recursos apenas após as requisições terminarem
process.exit(0);
});
});A razão pela qual essa ordem importa é o próprio event loop: o loop do Node mantém um processo vivo exatamente enquanto ele tiver timers pendentes, handles abertos ou trabalho inacabado (veja O Event Loop do Node.js). Chamar server.close() não mata conexões em andamento - ele para o servidor de aceitar novas e deixa o loop continuar rodando até que as requisições existentes completem naturalmente, o que é precisamente o comportamento de drain que um supervisor espera.
Exit é o estágio final - seja um process.exit(0) limpo após o draining terminar, ou um SIGKILL do supervisor se o processo não terminar dentro de seu período de graça. SIGKILL não pode ser capturado ou atrasado; é a garantia de força bruta do supervisor de que um processo travado não atrasará um deploy para sempre.
O modelo de ciclo de vida parece simples isoladamente, mas a produção adiciona casos extremos reais ao seu redor.
Exceções não capturadas e rejeições não tratadas não se encaixam claramente em nenhum dos cinco estágios - elas deveriam ser excepcionais. A própria orientação do Node é que, uma vez que uma uncaughtException dispare, o estado interno do processo pode estar corrompido de maneiras que são inseguras para continuar servindo; o padrão seguro é registrar o erro, tentar um desligamento limpo rápido e deixar o supervisor reiniciar um processo novo, em vez de tentar "capturar e continuar" indefinidamente.
Múltiplos estágios de supervisão frequentemente se empilham. Um contêiner pode rodar sob PM2 para reinícios em nível de processo, dentro de um pod gerenciado pelo Kubernetes para agendamento e escalonamento, atrás de um balanceador de carga que possui sua própria cadência de verificação de integridade - cada camada perguntando uma versão de "esta instância está pronta" independentemente, e cada uma com seu próprio timeout que deve ser maior que o da camada inferior ou os desligamentos competirão entre si.
O período de graça é um número operacional real, não um padrão para deixar intocado. Muito curto, e requisições lentas são mortas no meio do caminho durante cada deploy; muito longo, e um processo genuinamente travado bloqueia um deploy ou redução de escala por minutos. Obter esse número certo requer conhecer sua duração real de p99 de requisição sob carga, não adivinhar.
Observabilidade é o loop de feedback que torna todo este modelo confiável. Logs estruturados para stdout, IDs de requisição e métricas em nível de processo (latência do event loop, memória, handles abertos) são o que permitem a um operador confirmar que um deploy realmente drenou com sucesso em vez de presumir que o fez.
| Supervisor | Força | Fraqueza | Melhor Ajuste |
|---|---|---|---|
| systemd | Nativo da VM, sem tempo de execução adicional, políticas de reinício maduras | Sem roteamento de verificação de integridade ou escalonamento integrados | VMs de serviço único, implantações simples em bare-metal |
| PM2 | Recarregamento de tempo zero de inatividade integrado, modo cluster fácil em uma caixa | Não é um orquestrador real - sem agendamento multi-host | Pequenas equipes em algumas VMs, sem Kubernetes |
| Kubernetes | Sondas de liveness/readiness, implantações contínuas, autoescalonamento, multi-host | Complexidade operacional real; muito para aprender e executar | Frotas de múltiplos serviços que precisam de escalonamento e autocura |
| Serverless (ex: Lambda) | Nenhum ciclo de vida de processo para gerenciar - a plataforma é dona do start/stop | Cold starts, limites de tempo de execução, modelo mental completamente diferente | Cargas de trabalho esporádicas ou infrequentes, funções orientadas a eventos |
PM2 & systemd e Implantações de Tempo Zero de Inatividade transformam essa comparação em configuração concreta; Iniciadores de Runbook On-Call cobre o que verificar quando uma transição de ciclo de vida falha em produção.
SIGTERM significa que o processo está sendo morto." Significa que o supervisor está pedindo ao processo para parar - espera-se que o processo termine o trabalho em andamento primeiro; SIGKILL, não SIGTERM, é o forçoso e não pode ser interceptado.server.close() descarta qualquer requisição ainda em andamento." Ele para de aceitar novas conexões; requisições já sendo tratadas completam normalmente porque o event loop continua rodando até que elas o façam.A sequência pela qual um processo passa sob supervisão - start, ready, serving, draining, exit - onde um supervisor externo, não o próprio processo, decide quando a maioria das transições deve começar.
Em um laptop, nada mais depende do tempo exato de parada do processo. Em produção, um balanceador de carga está roteando tráfego ao vivo para ele, um deploy está tentando substituí-lo sem perder requisições, e um orquestrador precisa de um sinal confiável para quando é seguro rotear tráfego para lá - nada disso existe fora de um ambiente supervisionado.
Liveness pergunta "este processo deve ser reiniciado porque algo está errado?", enquanto readiness pergunta "o tráfego deve ser roteado para cá agora?". Um processo abrindo um pool de banco de dados na inicialização está vivo, mas ainda não pronto; um processo travado em um lock pode ainda responder a uma verificação de liveness enquanto é incapaz de servir requisições reais, que é por que algumas equipes adicionam uma verificação de liveness mais rigorosa também.
O supervisor (systemd, Kubernetes, PM2) envia o sinal SIGTERM em nível de SO para o PID do processo. O Node expõe isso como um evento process.on('SIGTERM', ...) que você pode manipular; sem um manipulador, o comportamento padrão do Node é sair imediatamente, o que pula qualquer draining.
server.close() para o servidor de aceitar novas conexões, mas não força o fechamento das existentes - o event loop continua rodando porque essas requisições em andamento ainda são trabalho pendente, e o processo só sai quando elas terminam e todos os handles abertos são liberados.
O período de graça do supervisor expira e ele envia SIGKILL, que termina o processo imediatamente e não pode ser capturado, atrasado ou limpo depois - qualquer requisição ainda em andamento naquele momento é descartada.
Geralmente não - uma exceção não capturada significa que um erro escapou de todos os manipuladores na pilha de chamadas, o que pode deixar o estado interno (conexões abertas, dados em memória parcialmente atualizados) em uma condição desconhecida. O padrão mais seguro é registrá-lo, desligar de forma limpa e deixar o supervisor iniciar um processo novo.
O código de manipulação de sinais em sua aplicação é o mesmo em ambos os casos - é o comportamento do supervisor ao redor dele que difere. O Kubernetes adiciona um endpoint de sonda de prontidão que a aplicação deve expor e um período de graça definido (terminationGracePeriodSeconds) que o cluster impõe, além do mesmo padrão SIGTERM-then-SIGKILL que systemd e PM2 também usam.
Geralmente porque a sonda de prontidão não falha cedo o suficiente na sequência de drain, então o balanceador de carga continua enviando novas requisições para uma instância que já começou a desligar - a correção é a ordem: falhar a prontidão primeiro, depois parar de aceitar conexões, depois deixar o trabalho em andamento terminar.
Não - um crash é uma saída não planejada, geralmente de um erro não capturado ou de ser morto sem aviso, enquanto um desligamento gracioso é uma sequência planejada e sinalizada que o processo controla o ritmo (dentro de seu período de graça). Ferramentas de runtime-ops assumem que crashes são excepcionais e desligamentos são rotineiros.
O event loop só sai quando não tem timers pendentes, handles abertos (como um servidor escutando ou um socket aberto) e I/O enfileirado - cada um desses é efetivamente um voto para manter o processo vivo, que é por que handles vazados (uma conexão de banco de dados não fechada, por exemplo) podem impedir um processo de sair limpo.
Apenas superficialmente - uma plataforma serverless é dona do ciclo de vida start/stop e geralmente não lhe dá nenhuma janela de manipulação de sinais, então o estágio de "draining" em grande parte não se aplica. Ainda vale a pena conhecer o modelo, porque mover um serviço de longa duração para serverless (ou de volta) significa raciocinar sobre um ciclo de vida genuinamente diferente, não apenas um alvo de deploy diferente.
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (Active LTS) e TypeScript 5.6+.
Revisado por Chris St. John·Última atualização: 15 de jul. de 2026