logo site seligadev
Como evitar requisições travadas, vazamento de recursos e falhas silenciosas em produção

Como evitar requisições travadas, vazamento de recursos e falhas silenciosas em produção

Jander Nery

Jander Nery

icon social media linkedinicon social media Xicon social media youtubeicon social media instagramicon social media facebookicon social media github

Se você já trabalhou com Node.js por tempo suficiente, provavelmente já viu esse cenário:

  • Uma requisição chega
  • Tudo parece normal nos logs
  • CPU baixa, memória estável
  • Mas… a requisição nunca termina

Sem erro.
Sem resposta.
Apenas esperando.

Nove em cada dez vezes, isso não é mágica. É um problema de timeout.

Timeouts no Node.js são um dos aspectos mais:

  • mal compreendidos
  • mal configurados
  • e perigosamente ignorados em sistemas de produção

Muitas equipes:

  • Não configuram timeouts
  • Acham que os padrões são suficientes
  • Ou colocam valores aleatórios sem entender

Resultado?

  • Requisições travadas
  • Sockets presos
  • Vazamento de recursos
  • Falhas em cascata
  • Péssima experiência do usuário

Por que timeouts são mais importantes do que você imagina

Antes de tudo:

👉 Timeout não é sobre ser rápido — é sobre ser seguro.

Eles protegem seu sistema contra:

  • Dependências lentas ou travadas
  • Problemas de rede
  • Falhas parciais
  • Deadlocks
  • Esperas infinitas
  • Falta de recursos

Node.js é orientado a eventos.
Se algo trava… todo o resto sofre.

Sem timeouts:

  • Sockets ficam abertos
  • Promises nunca resolvem
  • Memória cresce lentamente
  • Event loop fica lento
  • Throughput cai

E o pior:

👉 O sistema parece saudável… até quebrar de repente.


1. Nunca confie nos timeouts padrão

Os defaults do Node.js geralmente são:

  • Muito altos
  • Inconsistentes
  • Ou simplesmente inexistentes

Exemplos:

  • HTTP server → pode ser infinito
  • fetch / axios → sem timeout
  • banco de dados → muito alto
  • DNS → pode travar

👉 Defaults são permissivos, não seguros.

Boas práticas

  • Defina timeouts explicitamente
  • Trate “sem timeout” como bug
  • Documente latência esperada

2. Use timeouts diferentes para cada operação

Erro comum:

“Vamos colocar tudo em 30 segundos”

Isso espalha falhas lentas pelo sistema.

Pense em categorias de latência

  • Cache → milissegundos
  • APIs internas → poucos segundos
  • APIs externas → variável
  • Banco → depende da query

Boas práticas

  • Timeout por dependência
  • Baseado em P95, não no pior caso
  • Falhar rápido quando possível

3. Sempre defina timeout em chamadas HTTP externas

Por padrão:

  • fetch → sem timeout
  • axios → sem timeout
  • http.request → pode travar

👉 Resultado: sua aplicação pode esperar para sempre.

O que acontece

  • Socket fica aberto
  • Memória é consumida
  • Requisições acumulam
  • Sistema entra em colapso

Boas práticas

Definir:

  • Timeout de conexão
  • Timeout de resposta
  • Timeout total

E tratar erros de timeout corretamente.


4. Use AbortController (não Promise.race)

Muita gente faz isso:

Promise.race([
doRequest(),
new Promise((_, reject) =>
setTimeout(() => reject(new Error("Timeout")), 5000)
)
])

Problema:

  • A requisição continua rodando
  • Recursos não são liberados

👉 Você cancelou a Promise, mas não a operação.

Solução

Use AbortController

  • Cancela a requisição
  • Fecha sockets
  • Libera recursos

5. Configure timeouts no servidor

O Node possui vários:

  • server.timeout
  • headersTimeout
  • requestTimeout
  • keepAliveTimeout

Se mal configurados:

  • Clientes lentos ocupam conexões
  • Sockets ficam abertos
  • Sistema degrada

Boas práticas

  • Limite parsing de headers
  • Limite corpo da requisição
  • Feche conexões ociosas

6. Trate timeout de banco como sinal de problema

Timeout no banco significa:

  • Query lenta
  • Banco sobrecarregado

Ignorar isso causa:

  • Retries em cascata
  • Travamento
  • Latência alta

Boas práticas

  • Timeout de query baixo
  • Timeout de conexão definido
  • Monitorar frequência

7. Nunca faça retry cego após timeout

Timeout + retry = pode piorar tudo

Por quê?

Se o sistema já está lento:

  • Retry aumenta carga
  • Amplifica falha
  • Prolonga outage

👉 Isso é chamado de retry storm

Boas práticas

  • Backoff
  • Jitter
  • Circuit breaker
  • Limitar tentativas

8. Propague timeouts entre serviços

Problema comum:

  • Cliente cancela
  • Backend continua processando

Resultado:

  • Trabalho inútil
  • Estado inconsistente

Boas práticas

  • Propagar timeout
  • Cancelar processamento
  • Respeitar desconexão

9. Monitore timeouts como métrica principal

Muitos monitoram:

  • CPU
  • Memória
  • Erros

Mas esquecem:

  • Taxa de timeout

Por que importa?

Timeout aumenta:

  • Antes de erro
  • Antes de CPU subir

👉 É sinal antecipado de problema


10. Projete pensando em falha

Erro comum:

  • Assumir que tudo funciona

Realidade:

  • Falhas acontecem o tempo todo

👉 Timeout não é exceção — é fluxo normal

Boas práticas

  • Esperar falhas
  • Tratar corretamente
  • Proteger o sistema

Conclusão

Timeouts não são detalhe de configuração.

Eles definem:

  • Comportamento sob carga
  • Propagação de falhas
  • Resiliência do sistema

Bons timeouts

  • Falham rápido
  • Protegem o sistema
  • Melhoram UX

Maus timeouts

  • Escondem problemas
  • Gastam recursos
  • Causam incidentes

👉 Se você está construindo APIs, SaaS ou sistemas robustos em Node.js:

Timeout precisa ser tratado como parte da arquitetura — não detalhe.