# Quando 40 aplicações dividem destino: por que saímos do gerenciador de processos

> Um watchdog alheio derrubava nosso ERP a cada quatro minutos. A causa não era bug nosso — era compartilhar o mesmo supervisor com dezenas de outros processos.

Publicado em 2026-08-11 por Time Orion · Blog da Orion
Versão canônica: https://orion.moe/blog/systemd-em-vez-de-pm2
Índice do blog: https://orion.moe/blog

---

Durante meses, o ERP de um cliente caía sozinho. Não com padrão de vazamento de memória, não sob carga, não depois de deploy: caía em horários aleatórios, várias vezes por dia, com 502 para o usuário e volta em segundos.

O log da aplicação não mostrava nada. Ela não travava — ela **era terminada**.

## A causa

O servidor rodava dezenas de aplicações sob o mesmo gerenciador de processos. Entre elas, uma de terceiros com um watchdog próprio que, ao detectar um problema **nela mesma**, executava um comando de manutenção do gerenciador como remediação.

Esse comando recicla o daemon supervisor inteiro — e, com ele, **todos os processos gerenciados**.

Num dia, isso aconteceu 43 vezes. O ERP caiu 43 vezes por um problema que não era dele, disparado por um watchdog que estava fazendo exatamente o que tinha sido programado para fazer.

O nome disso é **destino compartilhado**: processos independentes que caem juntos porque dependem do mesmo supervisor.

## A correção

Duas frentes, e as duas eram necessárias.

**Curto prazo:** corrigimos os watchdogs alheios para reiniciar apenas o próprio serviço, em vez de reciclar o daemon.

**Estrutural:** tiramos o ERP do gerenciador compartilhado e o colocamos numa unidade de serviço própria do sistema operacional. O init do sistema já é um supervisor — com isolamento por serviço, política de reinício e captura de log, sem intermediário que possa ser reciclado por engano.

## As três linhas que aprendemos a não mexer

A unidade de serviço tem três configurações que parecem detalhe e são estruturais:

**`Environment=HOME=/root`.** Sem isso, o processo não encontra as credenciais de git da máquina — e o mecanismo de auto-atualização quebra de um jeito que não aparece em teste, só no dia da atualização.

**`KillMode=process`.** Esta é a mais sutil. O modo padrão mata o grupo de controle inteiro no restart. O problema: a própria aplicação dispara trabalhos de longa duração destacados — inclusive o que executa a atualização e **reinicia o serviço**. Com o modo padrão, o restart matava o processo que tinha pedido o restart, no meio do trabalho. Destacar o processo do grupo não basta: o grupo de controle pega mesmo assim.

**`TimeoutStopSec` maior que o tempo de drenagem.** A aplicação leva alguns segundos para encerrar conexões com elegância. Timeout menor que isso transforma todo restart em encerramento forçado — e encerramento forçado no meio de uma escrita é como se cria dado inconsistente que ninguém explica depois.

## O que isso ensinou sobre supervisão

**Supervisor é infraestrutura crítica, e destino compartilhado é uma decisão — não um detalhe.** Colocar N aplicações sob o mesmo supervisor significa aceitar que uma pode derrubar as outras. Para um servidor de desenvolvimento, tudo bem. Para produção de coisas que não podem cair, não.

**"Não é bug nosso" não conforta ninguém.** O usuário via 502. A causa era um watchdog de outro produto. A responsabilidade de não compartilhar destino era nossa.

**Log de aplicação não conta a história inteira.** Nada nos nossos logs indicava a causa; o que resolveu foi olhar quem enviou o sinal e quando. Quando um processo é terminado de fora, a evidência está no supervisor, não na aplicação.

## O deploy que veio junto

Aproveitamos a mudança para tornar o deploy **atômico**: a aplicação é construída num diretório novo e, só se a construção terminar bem, o diretório antigo é trocado pelo novo. Se falhar, nada é substituído e a versão no ar continua sendo a que funcionava.

Um detalhe que custou um incidente: num pipeline com saída redirecionada, o código de saída observado pode ser o do último comando da cadeia, e não o da construção. O resultado foi trocar uma versão boa por uma quebrada. Hoje a troca só acontece depois de conferir que o artefato de build existe de verdade.

## O resumo

Se uma aplicação sua não pode cair, ela não deve dividir supervisor com dezenas de outras que você não controla. O init do sistema faz esse trabalho com isolamento real — e as poucas linhas de configuração que parecem opinativas são justamente as que sustentam atualização e encerramento limpo.

É a mesma família de decisão de [preferir indisponibilidade a estado corrompido](/blog/405-nunca-apaga-credencial): escolher qual falha você aceita, antes de ela escolher por você.
