Timeout, retentativa e circuit breaker
Equipe AltiviaCloud · 5 de setembro de 2026 · 4 min de leitura
fetch sem timeout espera para sempre e trava o seu sistema, não o do fornecedor. Quais falhas merecem retentativa, por que o jitter não é preciosismo e o que fazer com o circuito aberto.
Toda integração externa vai falhar. A pergunta é o que o seu sistema faz nos trinta segundos seguintes — e a resposta padrão, "espera", costuma ser a pior de todas.
O timeout que não existe é o pior de todos
Boa parte dos clientes HTTP não tem timeout padrão razoável. fetch sem AbortSignal espera indefinidamente. Se o outro lado aceitou a conexão e parou de responder, sua requisição fica pendurada até alguém desistir — e ninguém desiste.
const res = await fetch(url, {
signal: AbortSignal.timeout(10_000),
});
Uma linha. Sem ela, uma lentidão do fornecedor vira exaustão de conexões do seu lado: cada requisição pendurada segura um recurso, e em poucos minutos não sobra nada para atender quem chega.
Escolha o número olhando o percentil, não a média. Se o p95 da chamada é 800ms, um timeout de 10s é folgado e ainda corta o caso patológico. Timeout de 60s não é conservador — é ausência de timeout com passos extras.
Nem toda falha merece retentativa
Repetir uma requisição que vai falhar de novo só multiplica o problema. A regra:
Repita: timeout, erro de conexão, 502, 503, 504. São falhas transitórias.
Não repita: 400, 401, 403, 404, 422. A requisição está errada; repetir não conserta.
Caso especial, 429: repita, mas só depois do tempo que o cabeçalho Retry-After indicar. Repetir antes disso é o que transforma um limite temporário em bloqueio — o assunto merece atenção própria.
Cuidado com POST. Repetir uma criação pode criar duas. Só repita se o outro lado aceitar chave de idempotência, ou se você puder verificar antes se a operação já aconteceu.
Espere de forma crescente, com ruído
Repetir de imediato, três vezes, é quase não repetir. Use intervalo que cresce:
const espera = Math.min(1000 * 2 ** tentativa, 30_000);
const jitter = Math.random() * 0.3 * espera;
await dormir(espera + jitter);
O jitter não é preciosismo. Sem ele, todos os seus processos que falharam juntos vão retentar no mesmo milissegundo, e o serviço que estava se recuperando leva o mesmo pico de novo. Rebanho sincronizado é como uma instabilidade curta vira uma queda longa.
Circuit breaker: parar de bater na porta
Retentativa resolve falha de uma requisição. Não resolve fornecedor fora do ar — nesse caso, cada requisição gasta o timeout inteiro antes de falhar, e a fila cresce.
O circuit breaker corta isso com três estados:
Fechado. Tudo normal, requisições passam. Um contador acompanha as falhas.
Aberto. Passou do limite de falhas, o circuito abre: as próximas requisições falham na hora, sem sair pela rede. É isso que devolve capacidade ao seu sistema — falhar rápido é melhor que falhar devagar.
Meio-aberto. Depois de um tempo, deixa passar uma requisição de teste. Se funcionar, fecha. Se falhar, abre de novo.
if (estado === "aberto") {
if (Date.now() < abertoAte) throw new Error("Circuito aberto");
estado = "meio-aberto"; // deixa uma passar
}
O ganho aparece quando o fornecedor volta: sem breaker, você o derruba de novo com toda a fila acumulada. Com breaker, uma requisição testa o terreno primeiro.
O que fazer enquanto o circuito está aberto
A parte que mais se esquece: degradar em vez de simplesmente falhar.
- Se há mais de um fornecedor, caia para o próximo — é o mesmo mecanismo, e o motivo pelo qual pular quem está falhando importa.
- Se o dado pode ser antigo, sirva o do cache e avise que é uma leitura defasada.
- Se a operação pode esperar, enfileire para depois em vez de devolver erro.
- Se nada disso serve, devolva erro claro e rápido, com indicação de quando tentar de novo.
Erro imediato e honesto é melhor experiência que trinta segundos de carregamento terminando em erro.
Onde ligar tudo
Não espalhe isso por cada chamada. Concentre em um lugar só — um wrapper do cliente HTTP — com timeout, política de retentativa e breaker configurados por integração. Assim cada nova chamada nasce protegida, em vez de depender de quem escreveu lembrar.
E instrumente: quantas vezes o circuito abriu, quantas retentativas aconteceram, qual o tempo real das chamadas. Sem esses números você ajusta os limites por palpite, e medir a integração é o que separa ajuste de chute.
É o mesmo raciocínio do failover que roda por trás dos números virtuais: quando um fornecedor não entrega, o pedido segue para o próximo.