Photo by Rene Bernal on Unsplash

Graceful shutdown com NodeJS

Karl Marx Alexander
investigacoesholisticas
3 min readSep 22, 2020

--

Se você trabalha com uma arquitetura distribuída, já deve ter ouvido falar no conceito de “graceful shutdown”. O princípio básico é que antes de se desligar, o seu processo deveria lidar com todas as tarefas em progresso.

Em um mundo de cloud functions e orquestração, é quase impossível que seu serviço não seja reiniciado algumas vezes, e saber lidar com isso pode fazer uma grande diferença.

Montando a cama

Antes de mais nada, para que você possa tomar ações antes da interrupção de um processo é necessário que você saiba quando um desligamento foi iniciado. No NodeJS esses eventos podem ser capturados usando a variável global process:

Você pode ver a lista de sinais UNIX e seus significados aqui, alguns deles não estão disponíveis no Windows ou não devem ser usados para processos de usuário, mas são interessantes de se conhecer.

Lidando com os problemas

Depois de saber que um sinal de finalização foi emitido para o seu processo, o que pode querer dizer que o hardware vai ser desligado, ou que o seu pod será excluído do cluster, entre várias outras possibilidades dependendo do ambiente, agora é necessário lidar com as tarefas de desligamento antes de terminar o processo.

Um caso de uso comum é quando seu programa lida com arquivos grandes, e ao receber um sinal para ser finalizado precisa garantir que o processamento atual termine com um arquivo válido:

No exemplo, sempre que um sinal ‘SIGTERM’ for recebido e o arquivo ‘hugeFile’ ainda estiver sendo lido, o processo irá esperar o stream do arquivo ser fechado antes de finalizar.

Um ponto importante a se notar é que na linha 28 eu decidi usar a função fs.closeSync. Uma boa prática a se observar é tentar realizar o máximo de operações síncronas durante o desligamento, pois esse é um modo mais simples e seguro de garantir que todas as ações foram tomadas.

Erros inesperados

Até agora nós vimos como garantir que um processo termine sua execução ao receber um sinal do sistema, porém algumas vezes erros inesperados que levam a necessidade de interrupção acontecem.

Existe um modo usando a API built-in do node de lidar com esses problemas e continuar garantindo que seu processo finalize sua execução do melhor jeito possível.

Eventos de processo

A mesma variável global que nos ajuda a lidar com sinais do sistema no NodeJS pode ser usada para escutar alguns eventos inesperados que normalmente causariam a interrupção imediata do processo.

Existem dois eventos principais que são relativos a erros inesperados, unhandledRejection e uncaughtException, e ao adicionar um listener programaticamente nós podemos desviar o fluxo desses eventos e controlar a interrupção do processo Node:

Desse modo sempre que um erro inesperado acontecer, você pode garantir que seu processo realize todas as tarefas necessárias para ser “graciosamente” interrompido.

--

--

Karl Marx Alexander
investigacoesholisticas

The less smarter and Brazilian Feynman, Software engineer at Gaivota