DEV Community

Cover image for Quando o Banco Não Caiu: Um Incidente de Conexão Que Expôs um Problema de Resiliência na Aplicação
Marcos Vilela
Marcos Vilela

Posted on

Quando o Banco Não Caiu: Um Incidente de Conexão Que Expôs um Problema de Resiliência na Aplicação

Incidentes reais são excelentes testes de maturidade técnica. Eles revelam não apenas falhas de código, mas principalmente falhas de premissas arquiteturais.

Este artigo descreve a investigação de um incidente envolvendo perda de conexão com PostgreSQL em ambiente produtivo, durante um pico de eventos. O objetivo aqui não é apontar culpados, mas demonstrar capacidade analítica, organização de evidências e raciocínio estruturado de troubleshooting.

Contexto do Incidente

Durante um pico elevado de processamento de eventos, o backend perdeu conexão com o banco de dados e não conseguiu se recuperar automaticamente. O banco permaneceu saudável durante todo o período. A aplicação, porém, entrou em modo degradado e passou a retornar dados mockados ao invés de consultar o banco real.

Primeira Hipótese: Banco Instável?

Sempre que há perda de conexão, a suspeita inicial costuma ser:

  • Failover do RDS
  • Reinício automático
  • Exaustão de conexões
  • Saturação de CPU ou I/O

A investigação começou pelo lado do banco.

Evidências coletadas

  • Status do RDS permaneceu Available
  • Nenhum evento de failover
  • Nenhum reboot automático
  • Métricas de CPU e memória estáveis
  • Log do banco registrou:
could not receive data from client: Connection reset by peer
Enter fullscreen mode Exit fullscreen mode

Esse log é crucial. Ele indica que quem encerrou a conexão foi o cliente, não o banco. A hipótese de indisponibilidade do RDS foi descartada.

Mudança de Foco: Aplicação

Com o banco saudável, a análise passou para a aplicação.

Observações importantes:

  • O container continuou rodando (não houve restart)
  • Não houve crash
  • A API permaneceu respondendo
  • Porém, estava desconectada do banco

Isso é um estado perigoso: sistema aparentemente saudável, mas funcionalmente degradado.

Análise do Código

Ao revisar a implementação do serviço de banco de dados, foi identificado o seguinte padrão:

  • Existe uma variável interna isConnected
  • Após a primeira conexão bem-sucedida, essa variável é marcada como true
  • O sistema passa a assumir que o banco continuará disponível indefinidamente

Problemas estruturais identificados:

  1. isConnected é tratada como fonte de verdade permanente
  2. Não há mecanismo de recriação do pool
  3. Não existe estratégia de reconexão automática
  4. Falhas de socket não invalidam o estado interno
  5. O erro não força reinicialização do container

Durante o pico de eventos, o backend encerrou abruptamente o socket TCP.

Após isso:

  • O pool ficou inválido
  • isConnected permaneceu true
  • A aplicação acreditava estar conectada
  • Nenhuma nova tentativa de conexão foi realizada

Resultado: sistema ativo, porém inutilizável do ponto de vista de dados reais.

Causa Raiz

A causa raiz não foi indisponibilidade do banco.

Foi uma falha de resiliência na camada de aplicação.

O sistema foi projetado com a premissa implícita de que:

"Se conectou uma vez, permanecerá conectado."

Essa premissa não é válida em ambientes distribuídos.

Conexões TCP podem ser encerradas por:

  • Picos de carga
  • Timeouts
  • Saturação temporária
  • Interrupções de rede
  • Problemas internos do runtime

Sem mecanismo de reconexão, qualquer falha transitória se torna permanente até intervenção manual.

Ação Corretiva Imediata

A solução operacional foi simples:

  • Reset da task do backend
  • Pool recriado
  • Conexão restabelecida
  • Serviço normalizado

Isso confirmou o diagnóstico: o problema estava no estado interno da aplicação.

Lições Arquiteturais

Este incidente reforça princípios fundamentais de sistemas distribuídos:

  • Conexões não são permanentes.
  • Pools não são imutáveis.
  • Estado interno pode mentir.
  • Healthcheck deve validar dependências reais.
  • Resiliência não é opcional em cenários de alta carga.

O banco estava saudável. A infraestrutura estava saudável. O problema estava na suposição arquitetural.

Conclusão

O incidente demonstrou que o maior risco não estava na infraestrutura, mas na camada de aplicação. A reinicialização resolveu o estado atual, mas não corrige o problema estrutural. Sistemas robustos não apenas se conectam — eles sabem se reconectar.

E isso faz toda a diferença quando a carga aumenta e o comportamento real do sistema começa a divergir das premissas iniciais de projeto.

Foi uma lição aprendida, não atuei na camada da aplicação, mas no throubleshooting e resolução pontual do incidente, o que estava na minha alçada.

Top comments (0)