Imagine mil pessoas tentando entrar em um elevador lotado. Todas esperam exatamente cinco segundos e tentam de novo, ao mesmo tempo. O elevador continua lotado, então todas esperam mais cinco segundos — juntas — e tentam de novo. Ninguém entra, e a multidão na porta nunca dispersa. Isso é, quase literalmente, o que acontece quando mil integrações de API falham ao mesmo tempo e todas retentam no mesmo intervalo fixo.
O fenômeno tem nome técnico — retry storm — e é uma das causas mais comuns e menos compreendidas de “a API do fornecedor caiu de novo bem na hora da nossa campanha”. A solução, batizada de exponential backoff and jitter, foi formalizada pela AWS em um post de arquitetura de março de 2015 que se tornou referência padrão da indústria.
Este artigo explica por que retentar “na mesma hora” é pior do que não retentar, e o que muda quando se adiciona uma dose de aleatoriedade a esse processo.
O problema não é falhar. É todo mundo falhar junto
Falha pontual de rede é normal e esperada. O problema começa quando uma causa comum — um pico de tráfego, uma instabilidade momentânea do fornecedor, um deploy malfeito — derruba muitas chamadas simultaneamente. Se todas essas chamadas seguem a mesma lógica de retry, com o mesmo intervalo de espera, elas voltam a bater na porta do servidor exatamente no mesmo instante.
O resultado é um sistema que nunca se recupera: a primeira falha era passageira, mas a onda sincronizada de retries recria a sobrecarga, gera nova falha, e o ciclo se repete. De fora, parece que “a API caiu de novo” — mas, muitas vezes, quem está derrubando a API é a própria multidão de integrações tentando se reconectar ao mesmo tempo.
Por que retry linear não resolve
A primeira melhoria intuitiva é espaçar as tentativas: esperar 1 segundo, depois 2, depois 3. É melhor que tentar imediatamente, mas ainda tem um problema estrutural — se mil integrações começaram a falhar no mesmo segundo, elas continuam perfeitamente sincronizadas em cada tentativa seguinte. O espaçamento cresce, mas o alinhamento entre todas as chamadas nunca se desfaz.
| Estratégia | Como funciona | Resolve o retry storm? |
|---|---|---|
| Retry imediato | Tenta de novo assim que falha, sem espera | Não — pior cenário, sobrecarrega instantaneamente |
| Backoff linear | Espera 1s, 2s, 3s… entre tentativas | Não — todas as chamadas continuam sincronizadas |
| Backoff exponencial | Espera 1s, 2s, 4s, 8s… dobrando a cada tentativa | Parcialmente — reduz a frequência, mas mantém o alinhamento |
| Backoff exponencial + jitter | Mesma progressão exponencial, mais um valor aleatório somado a cada espera | Sim — quebra a sincronização entre as chamadas |
O backoff exponencial sozinho já é uma melhora real: espaçar 1s, 2s, 4s, 8s reduz drasticamente o volume total de tentativas em relação ao linear. Mas se a causa da falha foi um evento sincronizado — e na prática quase sempre é —, o exponencial puro ainda faz todas as integrações baterem juntas, só que com menos frequência.
O jitter: a peça que faltava
Jitter é simplesmente adicionar um valor aleatório à espera calculada. Em vez de “espere exatamente 4 segundos”, a regra vira “espere entre 2 e 4 segundos, sorteado a cada tentativa”. Com isso, mil integrações que falharam no mesmo instante não retentam mais no mesmo instante — elas se espalham ao longo de uma janela de tempo.
A metáfora do elevador ajuda aqui: em vez de a multidão inteira tentar entrar no mesmo segundo, cada pessoa espera um tempo levemente diferente antes de tentar de novo. O fluxo se distribui, e o elevador consegue absorver as tentativas uma a uma em vez de ser atropelado por todas ao mesmo tempo.
Tecnicamente, existem variações — jitter completo (a espera é totalmente aleatória dentro do teto exponencial) e jitter parcial (mantém uma base fixa e soma aleatoriedade por cima) — mas o princípio é o mesmo em qualquer variação: dessincronizar agentes independentes que reagem ao mesmo evento.
Onde isso aparece na operação de marketing
Você provavelmente já viu os sintomas sem saber o nome da causa:
- Rate limit estourado sem motivo aparente. Sua ferramenta de automação começa a receber erro 429 (“muitas requisições”) do fornecedor logo depois de uma instabilidade pontual — porque todas as tentativas de retry chegaram juntas, parecendo um ataque de tráfego.
- Campanha que “trava” no meio do disparo. Um provedor de e-mail transacional tem uma lentidão de 30 segundos, e todos os disparos em fila retentam simultaneamente assim que o provedor volta, gerando uma nova sobrecarga imediata.
- Integração que “se recupera sozinha depois de um tempo”. O padrão comum é a falha diminuir gradualmente conforme os retries se dessincronizam por conta própria — o que sugere que o comportamento correto (jitter) já deveria estar configurado desde o início, em vez de esperado como acaso.
A pergunta certa para dev e fornecedor
Se sua automação bate frequentemente em rate limit ou é bloqueada por excesso de chamadas, a causa mais provável não é volume genúno de tráfego — é falta de jitter no mecanismo de retry. As perguntas que valem fazer:
- Para o dev ou agência que mantém a integração: “O retry usa backoff exponencial com jitter, ou só espera um tempo fixo crescente?” Se a resposta for “tenta de novo depois de X segundos” sem menção a aleatoriedade, o retry storm é uma questão de tempo.
- Para o fornecedor da API: “Vocês documentam uma política recomendada de retry? Existe rate limit por segundo, e o que acontece se muitos clientes retentarem ao mesmo tempo após uma instabilidade de vocês?” Fornecedores maduros costumam documentar isso explicitamente — a ausência de resposta é um sinal.
Retry com jitter não é só para código de dev
A maioria dos integradores no-code populares — Zapier, Make, n8n — já implementa alguma forma de backoff no motor interno, mas a configuração exposta ao usuário costuma ser limitada: número de tentativas e intervalo entre elas, sem controle fino sobre jitter. Isso significa duas coisas práticas:
- Se você não configura nada, está usando o padrão da ferramenta — que pode ou não incluir jitter. Vale checar a documentação específica do integrador antes de assumir que está protegido.
- Para integrações críticas de alto volume, a melhor prática é um código customizado (via função serverless, por exemplo) em vez do motor genérico de um integrador — justamente para ter controle explícito sobre o algoritmo de retry.
O código de erro importa: nem toda falha merece retry
Um refinamento importante que costuma faltar em implementações apressadas: nem todo erro deveria disparar retry. A distinção relevante está no código de status HTTP retornado. Erros na faixa 5xx (falha do servidor) geralmente indicam problema transitório — o servidor pode se recuperar, e retentar faz sentido. Erros na faixa 4xx (falha do cliente) geralmente indicam um problema que retry não resolve — um erro de autenticação, um payload malformado, ou um recurso que simplesmente não existe vão continuar falhando exatamente da mesma forma a cada nova tentativa.
Retentar cegamente diante de um erro 401 (não autorizado) ou 400 (requisição malformada) não só desperdiça tempo e recurso, como pode mascarar um problema que precisa de intervenção humana imediata — uma credencial expirada, por exemplo, não vai se corrigir sozinha depois de oito tentativas com backoff crescente. Uma implementação madura de retry distingue explicitamente essas duas famílias de erro, aplicando backoff com jitter apenas à família que genuinamente se beneficia dele.
A relação com idempotência
Retry com jitter resolve quando tentar de novo. Ele não resolve o que acontece quando a tentativa repetida é processada duas vezes. Essa é uma preocupação separada, tratada pela chave de idempotência — e as duas técnicas trabalham juntas: o jitter evita que o retry sobrecarregue o servidor, a idempotência evita que o retry duplique o resultado. Uma automação bem construída para operações críticas de POST precisa das duas.
Quantas tentativas fazem sentido
Backoff com jitter resolve como espaçar as tentativas, mas fica em aberto uma segunda pergunta prática: quantas tentativas fazer antes de desistir e alertar um humano. Retentar indefinidamente parece mais seguro à primeira vista, mas tem um custo escondido — uma falha real e permanente (credencial expirada, endpoint desativado pelo fornecedor) gera uma cadeia infinita de tentativas fantasma, consumindo recurso e atrasando a descoberta do problema real por quem poderia corrigi-lo.
A prática recomendada é limitar a um número finito de tentativas — algo entre três e sete é comum, dependendo da criticidade da operação — e, ao esgotar esse limite, mover a operação para uma fila de “falha permanente” que gera alerta humano, em vez de continuar tentando silenciosamente para sempre. Isso transforma uma falha invisível (que só aparece quando alguém nota a ausência de um resultado esperado) numa falha visível e acionável.
Circuit breaker: a proteção complementar
Um padrão que frequentemente acompanha retry com jitter é o circuit breaker: depois de um número de falhas consecutivas contra o mesmo destino, o sistema para de tentar temporariamente — abre o circuito — em vez de continuar batendo numa API que já demonstrou estar fora do ar. Isso poupa tanto o sistema que está chamando (que para de gastar recurso em tentativas fadadas ao fracasso) quanto o fornecedor (que não recebe uma nova onda de tentativas enquanto ainda está se recuperando). Depois de um intervalo de espera, o circuito é testado de novo com cautela, e só volta a fechar completamente se a chamada de teste for bem-sucedida.
Próximos passos para revisar suas integrações
A ação concreta: identifique a integração da sua stack com maior volume de chamadas por minuto — geralmente é o envio de eventos para uma plataforma de anúncios, um CDP ou um ESP — e pergunte ao responsável técnico se o retry dela usa jitter. Se a resposta for incerta, é a integração certa para revisar antes da próxima campanha de grande volume.
Retry storm raramente aparece isolado: se uma integração sofre com isso, é provável que outras da mesma stack, construídas pela mesma equipe ou no mesmo integrador, tenham o mesmo problema. Vale a auditoria valer para o conjunto, não só para o sintoma mais visível.