DEV Community

Cover image for A aplicação estava saudável. O negócio estava parado.
William Scussel
William Scussel

Posted on

A aplicação estava saudável. O negócio estava parado.

Uma aplicação de produção começou a devolver erros de autenticação para usuários reais.

O primeiro impulso foi procurar uma queda de servidor, um processo travado ou algum problema no banco.

Nada disso tinha acontecido.

Os servidores estavam ativos. Os processos estavam rodando. O container continuava respondendo ao health check.

Mesmo assim, a operação estava parcialmente parada.

O teste que parecia inofensivo

Durante uma atividade normal de desenvolvimento, foi gerado um novo login contra um ERP externo.

A integração usava tokens de sessão fornecidos por esse ERP. A aplicação mantinha esses tokens em cache para não precisar autenticar a cada chamada.

O detalhe perigoso era que desenvolvimento e produção usavam a mesma credencial externa.

O fornecedor não tratava cada ambiente como uma identidade isolada. Um novo login podia invalidar ou deslocar uma sessão que a produção ainda estava usando.

Poucos minutos depois, a aplicação começou a receber respostas equivalentes a “login ou senha inválido” em várias operações do ERP.

O erro aparecia em massa, para usuários diferentes. Isso era um sinal importante: não era um registro específico nem um problema isolado de usuário. Era a autenticação da aplicação contra a dependência externa.

O servidor estava saudável

Esse tipo de incidente é perigoso porque os indicadores tradicionais continuam verdes.

O processo não caiu. O container não reiniciou. O endpoint de health check respondeu. O banco continuou disponível.

Mas a função principal da integração estava quebrada.

Em uma ocorrência, usuários perceberam o problema rapidamente e abriram chamados. Em outra, o erro ficou silencioso por dias. Os jobs continuavam executando, mas uma etapa importante retornava zero registros. Como não havia um alerta para esse resultado de negócio, a infraestrutura continuava reportando saúde.

Essa diferença merece uma definição explícita:

Saúde técnica significa que o sistema está executando.

Saúde operacional significa que ele está entregando o resultado esperado.

Uma não garante a outra.

A cadeia causal

O incidente não tinha uma única causa isolada. Ele era uma cadeia de decisões razoáveis que, combinadas, criaram um risco grande:

  1. Ambientes diferentes compartilhavam uma credencial externa.
  2. O fornecedor tinha regras de sessão concorrente que não estavam sob nosso controle.
  3. A aplicação reutilizava um token em cache e não tinha recuperação automática confiável.
  4. O token existia em mais de um lugar, como arquivo de ambiente, CI e Secret Manager.
  5. O deploy podia recriar configurações antigas.
  6. O health check verificava o processo, não a integração crítica.
  7. Os jobs não tinham alerta específico para volume de resultado inesperadamente zerado.

O primeiro incidente sugeriu que o fornecedor permitia apenas uma sessão por credencial. Testes posteriores indicaram uma hipótese mais cuidadosa: poderia existir um limite ou pool pequeno de sessões, com invalidação dos tokens mais antigos quando novas sessões eram criadas.

O tamanho exato desse limite não foi provado. Para a operação, porém, o efeito era o mesmo: gerar sessões novas contra uma credencial compartilhada podia derrubar uma sessão ainda usada pela produção.

Essa distinção é importante. Uma boa análise não transforma uma hipótese conveniente em fato só porque ela explica o primeiro sintoma.

O conserto emergencial

A recuperação imediata foi operacional:

  • Gerar tokens novos usando credenciais de autenticação mais estáveis.
  • Validar esses tokens contra endpoints reais antes de aplicá-los.
  • Atualizar as configurações do ambiente legado, do CI e do ambiente em nuvem.
  • Reiniciar os processos para que carregassem os valores novos.
  • Observar chamadas bem-sucedidas durante um período de estabilização.

Isso restaurou o serviço, mas ainda era um band-aid. Trocar o valor de um segredo não remove o risco de ele ser revogado novamente.

Também havia um problema de distribuição. Atualizar apenas o .env do servidor não bastava se o próximo deploy recriasse o arquivo a partir de um parâmetro antigo do CI.

A correção estrutural

O desenho da correção precisava eliminar a dependência de intervenção manual:

1. Separar ambientes de verdade

Desenvolvimento, homologação e produção precisam de credenciais externas diferentes sempre que o fornecedor permitir.

Quando isso não for possível, a restrição deve ser tratada como um risco formal, com procedimento de diagnóstico e controles explícitos.

2. Reautenticar automaticamente

A aplicação não deve depender indefinidamente de um token de sessão salvo no ambiente. Quando o token expira ou é rejeitado, o sistema precisa obter outro de maneira controlada.

3. Compartilhar o cache entre processos

Um cache em memória cria uma sessão diferente para cada processo. Com vários workers, cron e containers, a própria aplicação pode gerar sessões demais.

Um cache compartilhado reduz esse comportamento e torna o estado da autenticação visível para todos os processos.

4. Coordenar a reautenticação

Se vários processos perceberem o token inválido ao mesmo tempo, todos podem tentar fazer login. Isso cria uma nova rajada de sessões justamente no momento em que o sistema está se recuperando.

Um lock distribuído permite que apenas um processo faça a reautenticação. Os demais aguardam o novo token aparecer no cache compartilhado.

5. Monitorar o resultado do negócio

O health check precisa responder perguntas além de “o processo está vivo?”

  • A autenticação com o ERP está funcionando?
  • A última importação trouxe registros dentro do esperado?
  • A fila recebeu itens quando deveria?
  • A taxa de erro da dependência externa mudou abruptamente?

Nem toda checagem precisa ser uma chamada pesada em produção. Métricas de resultado, idade do último sucesso e alertas de volume anormal já capturam uma classe importante de falhas silenciosas.

O que esse incidente ensinou

O erro mais fácil de apontar seria o login manual. Ele foi o gatilho de uma ocorrência, mas não explica sozinho por que a produção era vulnerável.

O risco real estava na combinação de:

  • credencial compartilhada;
  • sessão externa com regras pouco conhecidas;
  • token sem renovação automática;
  • configuração replicada em vários lugares;
  • monitoramento sem visão do resultado operacional.

Esse padrão aparece em muitos contextos. Pode ser um ERP, uma API bancária, um gateway de pagamentos ou qualquer fornecedor que use sessões, tokens e limites próprios.

Quando uma integração é crítica, disponibilidade não pode ser medida apenas pelo estado do servidor.

Checklist para evitar o mesmo problema

  • Use credenciais distintas por ambiente.
  • Nunca gere login de desenvolvimento contra uma credencial de produção.
  • Documente se o fornecedor limita sessões ou invalida tokens antigos.
  • Tenha refresh ou reautenticação automática.
  • Use cache compartilhado quando houver múltiplos processos.
  • Coordene a recuperação com lock distribuído.
  • Mantenha uma fonte única para secrets e parâmetros de deploy.
  • Alimente alertas com métricas de negócio.
  • Teste também o caminho de falha da dependência externa.
  • Diferencie health check técnico de health check operacional.

A aplicação estava saudável. O negócio estava parado.

O objetivo da arquitetura e da operação é garantir que essas duas frases nunca mais possam ser verdadeiras ao mesmo tempo.

Top comments (0)