--:--:--

Erro 429 Too Many Requests: como usar Retry-After, backoff e jitter sem derrubar a API

Publicado em 2026-08-29T20:13:00Z · atualizado em 2026-08-29T19:13:12+00:00

O erro **429 Too Many Requests** significa que o servidor recebeu solicitações demais daquele cliente em determinado intervalo. A reação instintiva — repetir imediatamente até funcionar — costuma piorar o problema. O cliente aumenta a press

Fluxo de uma requisição limitada, espera calculada e nova tentativa controlada
Imagem de apoio ao tema do artigo.

Erro 429 Too Many Requests: como usar Retry-After, backoff e jitter sem derrubar a API

O erro 429 Too Many Requests significa que o servidor recebeu solicitações demais daquele cliente em determinado intervalo. A reação instintiva — repetir imediatamente até funcionar — costuma piorar o problema. O cliente aumenta a pressão justamente quando o serviço pediu redução de ritmo, acumula tarefas, desperdiça cota e pode transformar uma limitação temporária em falha prolongada.

Este guia mostra como diagnosticar a origem do 429 e construir uma política de retentativa que respeita Retry-After, aplica backoff exponencial com jitter, limita o número de tentativas e trata operações não idempotentes com cuidado. Os exemplos funcionam em JavaScript moderno e Python, sem bibliotecas externas.

Fluxo de uma requisição limitada, espera calculada e nova tentativa controlada Legenda: uma boa retentativa volta para a fila com atraso e orçamento definidos; ela não entra em um laço imediato.

O que o código 429 realmente informa

A RFC 6585 define 429 para indicar que o usuário enviou solicitações demais em certo período. A resposta pode trazer detalhes sobre a condição e o cabeçalho Retry-After, que informa quanto esperar. A limitação pode considerar endereço IP, chave de API, usuário autenticado, rota, organização ou uma combinação desses sinais.

Isso muda o diagnóstico. Se somente uma chave recebe 429, trocar DNS ou reiniciar o computador não resolve. Se todas as chaves falham ao mesmo tempo, pode haver uma cota global da conta. Se apenas uma rota pesada é limitada, reduzir chamadas em outra rota provavelmente não altera o resultado.

Registre, no mínimo, horário, método, rota sem dados sensíveis, status, tentativa, tempo de resposta e cabeçalhos de limite permitidos pelo provedor. Nunca grave tokens completos no log.

2026-08-17T10:15:31Z GET /v1/relatorios status=429 tentativa=1 retry_after=8

429, 503 e timeout não são a mesma falha

Um 429 atribui a limitação ao ritmo do cliente ou à cota associada a ele. Um 503 Service Unavailable comunica indisponibilidade temporária do serviço. Um timeout significa que o cliente não recebeu uma resposta conclusiva dentro do prazo. Os três casos podem aceitar retentativa, mas não devem compartilhar cegamente a mesma regra.

No 429, dê prioridade ao Retry-After. No 503, respeite esse cabeçalho quando presente e aplique backoff. Em timeout, primeiro avalie se a operação pode ter sido executada no servidor: repetir um pagamento, cadastro ou envio sem idempotência pode duplicar o efeito.

Erros permanentes, como 400 por JSON inválido ou 401 por credencial incorreta, não melhoram com espera. Retentar indiscriminadamente apenas esconde o defeito e consome recursos.

Como interpretar o cabeçalho Retry-After

Segundo a semântica HTTP, Retry-After pode ser um número inteiro de segundos ou uma data HTTP. Um cliente robusto entende os dois formatos e usa um limite máximo local, evitando permanecer bloqueado por uma resposta incorreta.

function parseRetryAfter(value, now = Date.now()) {
  if (!value) return null;

  const seconds = Number(value);
  if (Number.isFinite(seconds) && seconds >= 0) {
    return seconds * 1000;
  }

  const date = Date.parse(value);
  if (Number.isNaN(date)) return null;
  return Math.max(0, date - now);
}

Datas dependem do relógio do cliente e do servidor. Por isso, resultados negativos devem virar zero, e atrasos absurdos devem ser limitados pela política da aplicação. Se o cabeçalho não existir ou for inválido, calcule um atraso com backoff.

Por que repetir imediatamente cria uma tempestade

Imagine 100 tarefas recebendo 429 no mesmo segundo. Se todas repetirem a cada 100 milissegundos, serão mil novas requisições por segundo. Quando o limite reabrir, todas acordarão juntas e formarão outra onda. Esse comportamento é chamado de sincronização ou efeito manada.

O backoff exponencial aumenta a espera a cada falha: 1, 2, 4, 8 segundos. O jitter introduz aleatoriedade para espalhar os clientes no tempo. Assim, duas tarefas que falharam juntas deixam de repetir exatamente juntas.

Comparação entre repetição sincronizada e backoff com jitter distribuído no tempo Legenda: sem jitter, os picos reaparecem; com jitter, as tentativas ocupam janelas diferentes.

Uma forma simples de full jitter escolhe um valor aleatório entre zero e o teto exponencial:

function fullJitter(attempt, baseMs = 500, capMs = 30_000) {
  const ceiling = Math.min(capMs, baseMs * 2 ** attempt);
  return Math.floor(Math.random() * ceiling);
}

Cliente JavaScript reproduzível com fetch

O exemplo abaixo retenta apenas 429, 502, 503 e 504. Ele respeita Retry-After, aplica jitter quando o servidor não orienta uma espera, limita cada atraso e encerra após o orçamento de tentativas.

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

async function fetchWithRetry(url, options = {}, policy = {}) {
  const {
    maxAttempts = 5,
    baseDelayMs = 500,
    maxDelayMs = 30_000,
    timeoutMs = 15_000
  } = policy;

  const retryable = new Set([429, 502, 503, 504]);
  let lastError;

  for (let attempt = 0; attempt < maxAttempts; attempt++) {
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), timeoutMs);

    try {
      const response = await fetch(url, {
        ...options,
        signal: controller.signal
      });

      if (!retryable.has(response.status)) return response;
      if (attempt === maxAttempts - 1) return response;

      const instructed = parseRetryAfter(response.headers.get("retry-after"));
      const calculated = fullJitter(attempt, baseDelayMs, maxDelayMs);
      const delay = Math.min(maxDelayMs, instructed ?? calculated);
      await sleep(delay);
    } catch (error) {
      lastError = error;
      if (attempt === maxAttempts - 1) throw error;
      await sleep(fullJitter(attempt, baseDelayMs, maxDelayMs));
    } finally {
      clearTimeout(timer);
    }
  }

  throw lastError ?? new Error("Falha sem resposta");
}

Para testar sem depender de uma API real, substitua fetch por uma função que devolva duas respostas 429 e depois uma 200. O teste deve confirmar três chamadas e duas esperas. Em testes automatizados, injete também a função sleep, evitando esperar de verdade.

Versão equivalente em Python

Este exemplo usa apenas a biblioteca padrão. urllib.error.HTTPError representa respostas HTTP com status de erro; o corpo e os cabeçalhos continuam disponíveis.

import email.utils
import random
import time
import urllib.error
import urllib.request
from datetime import datetime, timezone

RETRYABLE = {429, 502, 503, 504}

def retry_after_seconds(value):
    if not value:
        return None
    try:
        return max(0.0, float(value))
    except ValueError:
        parsed = email.utils.parsedate_to_datetime(value)
        if parsed.tzinfo is None:
            parsed = parsed.replace(tzinfo=timezone.utc)
        return max(0.0, (parsed - datetime.now(timezone.utc)).total_seconds())

def request_with_retry(url, max_attempts=5, base=0.5, cap=30.0):
    for attempt in range(max_attempts):
        try:
            return urllib.request.urlopen(url, timeout=15)
        except urllib.error.HTTPError as exc:
            if exc.code not in RETRYABLE or attempt == max_attempts - 1:
                raise
            instructed = retry_after_seconds(exc.headers.get("Retry-After"))
            calculated = random.uniform(0, min(cap, base * (2 ** attempt)))
            time.sleep(min(cap, instructed if instructed is not None else calculated))

Em um serviço com muitas requisições simultâneas, não bloqueie uma thread para cada espera. Use a alternativa assíncrona da sua pilha ou devolva o item a uma fila com horário de próxima execução.

Idempotência: quando uma retentativa pode duplicar dados

Métodos de leitura como GET normalmente são seguros para repetir. Uma requisição POST pode ter sido processada mesmo que a resposta tenha se perdido. O cliente vê timeout, repete e cria duas cobranças, dois pedidos ou dois registros.

A solução é uma chave de idempotência definida pelo cliente e persistida pelo servidor. Duas requisições com a mesma chave e conteúdo representam a mesma operação lógica. O servidor guarda o resultado da primeira e o devolve nas repetições, em vez de executar novamente.

POST /v1/pedidos HTTP/1.1
Idempotency-Key: pedido-2026-08-17-00042
Content-Type: application/json

A chave deve ser estável para aquela operação, não criada novamente a cada tentativa. Também precisa de escopo, prazo de retenção e regra para rejeitar a mesma chave com conteúdo diferente. Se a API de terceiros não oferece idempotência, limite retentativas de operações mutáveis e consulte o estado antes de repetir.

Controle de concorrência vem antes da retentativa

Se um processo dispara 500 requisições simultâneas contra uma cota de 20 por segundo, nenhuma fórmula de backoff corrige a causa. Coloque um limitador antes do cliente: fila, semaphore, balde de fichas ou janela deslizante. Retentativa é proteção contra variação; controle de concorrência é planejamento de carga.

Uma fila simples pode manter no máximo cinco operações em voo e liberar uma nova quando outra termina. Outra camada limita a taxa ao longo do tempo. O ideal usa as duas dimensões, porque cinco chamadas lentas e cinco chamadas muito rápidas pressionam a API de maneiras diferentes.

Mapeie esse fluxo antes de codificar. A ferramenta de fluxogramas do IATechNerds ajuda a registrar entrada, fila, chamada, espera e fila de falhas. Para organizar requisitos e responsáveis, consulte também as ferramentas online.

Orçamento total, cancelamento e fila de falhas

maxAttempts sozinho não garante prazo. Cinco esperas podem ultrapassar o tempo aceitável do usuário. Defina um orçamento total, como 45 segundos, e pare quando a próxima espera excedê-lo. Propague cancelamento: se a tela foi fechada ou a tarefa perdeu validade, não mantenha retentativas órfãs.

Depois do limite, preserve contexto suficiente para análise e encaminhe a operação a uma fila de falhas, quando aplicável. Não deixe um laço infinito segurando memória. Uma falha explícita e observável é melhor que uma tarefa silenciosamente presa.

Métricas úteis incluem: proporção de 429, tentativas por operação, tempo acumulado de espera, sucesso após retentativa e esgotamento do orçamento. Acompanhe por rota e credencial anonimizada, porque uma média global pode esconder um consumidor problemático.

Cotas compartilhadas entre processos e usuários

Um limitador em memória funciona para uma única instância. Se quatro servidores usam a mesma chave de API, cada um pode acreditar que ainda possui toda a cota. A soma ultrapassa o limite mesmo que cada processo, isoladamente, pareça comportado. Nesse cenário, o orçamento precisa ser coordenado em uma fila central, armazenamento compartilhado ou serviço de limitação distribuída.

Não use uma chave diferente apenas para contornar a política do provedor. Separe credenciais quando existem consumidores, ambientes e permissões realmente distintos, conforme os termos da API. Desenvolvimento não deve gastar a cota de produção; tarefas de baixa prioridade não devem bloquear operações interativas.

Alguns provedores devolvem cabeçalhos como limite total, saldo restante e horário de renovação. Os nomes variam e não substituem a documentação específica. Trate-os como sinais de planejamento: reduza o ritmo antes de chegar a zero, mas continue preparado para 429 porque a contagem do servidor é a autoridade.

Também defina justiça entre usuários. Uma importação de 50 mil itens não deveria consumir todas as vagas e impedir uma consulta curta. Filas por prioridade ou round-robin por cliente evitam que um produtor monopolize a cota. A prioridade precisa ter envelhecimento para que trabalhos de fundo não fiquem presos para sempre.

Por fim, calcule a vazão esperada. Uma cota de 600 chamadas por minuto não significa que 600 chamadas no primeiro segundo serão aceitas. O servidor pode usar uma janela móvel ou rajada máxima. Distribuir dez solicitações por segundo é mais previsível que descarregar o minuto inteiro de uma vez. Registre qual hipótese foi adotada e ajuste-a com métricas, sem tentar descobrir limites por carga agressiva.

Como testar sem provocar bloqueio em produção

Crie um servidor local determinístico que responda 429 nas duas primeiras chamadas e 200 na terceira. No Node.js:

import http from "node:http";

let calls = 0;
const server = http.createServer((req, res) => {
  calls += 1;
  if (calls <= 2) {
    res.writeHead(429, { "Retry-After": "1" });
    return res.end("espere");
  }
  res.writeHead(200, { "Content-Type": "application/json" });
  res.end(JSON.stringify({ ok: true, calls }));
});

server.listen(8080);

Execute o cliente contra http://localhost:8080, confirme que leva aproximadamente dois segundos e encerre o servidor. Depois cubra casos de cabeçalho inválido, data passada, 400 não retentável, timeout, cancelamento e esgotamento do orçamento. Não use uma API real para “ver quantas chamadas aguenta”; além de desperdiçar cota, isso pode violar as regras do serviço.

Checklist para corrigir o erro 429

Antes de considerar o problema resolvido, confirme:

  • o cliente distingue 429 de erros permanentes;
  • Retry-After aceita segundos e data HTTP;
  • há backoff com jitter quando o cabeçalho não existe;
  • atraso, tentativas e tempo total têm teto;
  • a concorrência é limitada antes do envio;
  • operações mutáveis usam idempotência ou reconciliação;
  • tokens e dados pessoais não aparecem em logs;
  • cancelamentos interrompem novas tentativas;
  • testes simulam falhas sem atacar serviços reais;
  • métricas mostram quando a política está falhando.

Para experimentar trechos e organizar dados de teste localmente, visite a biblioteca de Python e o catálogo de ferramentas do site.

Documentação primária

Nota de produção

Rascunho produzido a partir da intenção de busca “como corrigir erro 429 Too Many Requests”, com exemplos autorais e reproduzíveis. A semântica do status e do cabeçalho foi conferida em RFCs; o texto não depende de marcas ou cotas específicas. Antes da publicação, a revisão humana deve executar os exemplos, verificar os links internos e adaptar a voz editorial final.

Camada extra: como tomar uma decisão melhor neste cenário

Para levar Erro 429 Too Many Requests: como usar Retry-After, backoff e jitter sem derrubar a API além de uma receita de passos, vale transformar o procedimento em um pequeno método: observar, isolar, alterar uma variável e conferir o resultado.

O erro **429 Too Many Requests** significa que o servidor recebeu solicitações demais daquele cliente em determinado intervalo. A reação instintiva — repetir imediatamente até funcionar — costuma piorar o problema. O cliente aumenta a press A ideia central pode ser testada com quatro perguntas: o que foi observado, qual hipótese explica o sintoma, qual mudança é reversível e qual evidência prova que funcionou. Esse encadeamento evita que uma coincidência seja confundida com causa e torna o procedimento repetível por outra pessoa.

Qualidade de IA precisa de um teste, não de uma impressão

Para HTTP, API, 429, backoff, escolha três tarefas representativas: uma simples, uma ambígua e uma em que a resposta possa ser conferida em fonte primária. Compare utilidade, rastreabilidade, privacidade, velocidade e quantidade de correção humana necessária. Uma resposta elegante não compensa uma citação inexistente ou uma conclusão que não pode ser reproduzida.

Separe ainda o que pode sair do dispositivo do que deve permanecer local. Dados públicos toleram fluxos diferentes de documentos internos, contratos, informações pessoais ou bases de clientes. A escolha entre processamento local e nuvem deve ser feita pelo risco do conteúdo, não apenas pela conveniência da interface.

Grade de avaliação prática

CritérioPerguntaEvidência
CorreçãoA resposta bate com a fonte?Checagem independente
RastreabilidadeÉ possível localizar de onde veio?Citação ou trecho verificável
PrivacidadeQue dado sai do dispositivo?Política e configuração
EsforçoQuanto trabalho humano resta?Tempo de revisão

O ponto em que a IA deixa de ajudar

Se a tarefa exige precisão absoluta e a saída não pode ser validada, a automação deve ser limitada a apoio: localizar trechos, organizar opções ou preparar uma primeira versão. A decisão final precisa permanecer com alguém capaz de verificar a fonte e assumir a responsabilidade pelo resultado.

Checklist de fechamento

  • Registre o estado inicial antes de alterar qualquer coisa.
  • Faça uma mudança por rodada e anote o efeito.
  • Teste um caso normal, um caso-limite e o cenário que originalmente falhou.
  • Confirme que a solução continua válida depois de reiniciar, reabrir ou repetir o fluxo.
  • Guarde uma forma de voltar ao estado anterior quando a alteração for destrutiva.

Esse método acrescenta profundidade sem transformar o artigo em teoria abstrata: o leitor entende por que cada passo existe e como reconhecer quando a situação exige uma decisão diferente.

#HTTP #API #429 #backoff #JavaScript