Limitação de Taxa da API — Cabeçalhos, Retorno Exponencial e Sobrevivência ao Código 429
Você atingiu um 429. A API está dizendo para reduzir a velocidade. Aqui está como decodificar os cabeçalhos X-RateLimit-*, entender o Retry-After e implementar retrocesso exponencial com jitter, para que suas integrações lidem com limites de taxa de forma graciosa, em vez de bater repetidamente no servidor.
Você recebeu um 429. Talvez seu manipulador de webhook tenha travado. Talvez um lote de trabalho tenha sido silenciosamente descartado. A API retornou 'Muitas solicitações' e uma grande quantidade de cabeçalhos de resposta que você provavelmente já passou.
Esses cabeçalhos contêm toda a história. Aqui está como lerlos e como escrever uma lógica de tentativa que não agrava o problema.
Os Cabeçalhos que realmente importam
A maioria das APIs com limite de taxa retorna alguma variação desses cabeçalhos em cada resposta — não apenas em respostas com código 429:
- X-RateLimit-Limit — o número total de solicitações permitidas na janela atual. A API REST do GitHub permite 5.000 solicitações por hora para usuários autenticados; as solicitações não autenticadas têm limite de 60.
- X-RateLimit-Remaining — o número de solicitações restantes na janela atual. Quando esse valor atinge zero, a próxima solicitação retorna um 429.
- X-RateLimit-Reset — o momento em que a janela será redefinida, como um timestamp do Unix. Este é o cabeçalho que a maioria dos desenvolvedores ignora e o mais útil.
- X-RateLimit-Used (específico do GitHub) — número de solicitações consumidas até agora. É uma espécie de reflexo de
Limit - Remainingmas útil para verificações de consistência. - Retry-After — aparece apenas em respostas com código 429. Pode ser um número de segundos para esperar ou uma string de data HTTP. Se a API o enviar, use-o — é mais preciso do que qualquer cálculo que você faça por si mesmo.
Os cabeçalhos reais da resposta do GitHub parecem assim:
X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4823
X-RateLimit-Reset: 1716998400
X-RateLimit-Used: 177
X-RateLimit-Resource: core
O X-RateLimit-Resource cabeçalho é específico do GitHub: eles mantêm pools separados de limite para REST, busca e GraphQL. Usar seu limite de busca (limitado a 30 solicitações por minuto) não afeta seu limite principal — e vice-versa.
Stripe é diferente
Stripe não usa X-RateLimit-* nomenclatura. Seus cabeçalhos têm prefixo diferente:
Stripe-Ratelimit-Limit: 100
Stripe-Ratelimit-Remaining: 97
Stripe-Ratelimit-Reset: 1716998460
E em um 429:
Retry-After: 30
O limite padrão do Stripe é 100 solicitações em modo ativo por segundo, não por hora. Isso importa mais do que parece: um loop importando 500 clientes pode esgotar esse limite em menos de 5 segundos se você não limitar as solicitações no seu lado.
O Stripe também distingue entre limites de taxa de solicitação e limites específicos de recursos (por exemplo, criar muitos clientes em um curto período). O corpo da resposta 429 especifica qual limite foi ultrapassado — sempre registre o corpo completo, não apenas o código de status.
Decodificando o Timestamp de Resset
O X-RateLimit-Reset valor é um timestamp do Unix. 1716998400 não diz nada de imediato, mas é fácil decodificar: use a Conversor de Timestamp Unix para converter em uma data legível no fuso horário UTC e ver exatamente quanto tempo falta até o reset.
No código: reset_time - time.now() dá o número de segundos até o reset da janela. Mas verifique X-RateLimit-Remaining primeiro — se ainda tem limite, não há necessidade de esperar.
O que o corpo da resposta 429 diz
O código de status 429 sozinho não é suficiente. O corpo da resposta geralmente especifica qual limite foi ultrapassado:
GitHub:
{
"message": "API rate limit exceeded for user ID 12345.",
"documentation_url": "https://docs.github.com/rest/overview/rate-limits"
}
Stripe:
{
"error": {
"code": "rate_limit",
"message": "Too many requests hit the API too quickly.",
"type": "invalid_request_error"
}
}
OpenAI vai além: a mensagem de erro especifica se você atingiu um limite de tokens por minuto ou de solicitações por minuto, o que muda completamente sua estratégia de tentativa. Sempre registre o corpo completo da resposta 429.
Retentativa exponencial com jitter
A solução simples: capture um 429, espere 1 segundo e tente novamente. Isso falha por duas razões:
- Se você tem múltiplos trabalhadores acessando o mesmo endpoint, todos eles esperarão 1 segundo e tentarão novamente simultaneamente — uma tempestade de tentativas sincronizadas que recreia o problema.
- 1 segundo é inútil se você esgotou um limite por hora ou por dia. Você simplesmente coletará 3.600 novos 429s.
A abordagem correta é a retentativa exponencial com jitter: cada tentativa espera mais tempo do que a anterior, com um componente aleatório para dessincronizar trabalhadores concorrentes.
import time
import random
import requests
def fetch_with_backoff(url, headers, max_retries=5):
base_delay = 1 # seconds
for attempt in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code != 429:
return response
# Prefer Retry-After if the API provides it
retry_after = response.headers.get("Retry-After")
if retry_after:
wait = int(retry_after)
else:
# Fall back to X-RateLimit-Reset
reset = response.headers.get("X-RateLimit-Reset")
if reset:
wait = max(0, int(reset) - int(time.time()))
else:
# Pure exponential backoff with full jitter
cap = 60 # max wait: 60s
wait = random.uniform(0, min(cap, base_delay * (2 ** attempt)))
print(f"Rate limited. Attempt {attempt + 1}/{max_retries}. Waiting {wait:.1f}s")
time.sleep(wait)
raise Exception(f"Max retries exceeded after {max_retries} attempts")
A ordem de prioridade nessa implementação é deliberada:
- Retry-After primeiro — se a API informar exatamente quanto tempo esperar, use isso. Não tente adivinhar com seu próprio cálculo.
- X-RateLimit-Reset como alternativa — calcule os segundos até o reset em vez de adivinhar um atraso fixo.
- Jitter completo como último recurso —
random.uniform(0, cap)distribui as tentativas ao longo do intervalo de espera. O blog técnico da AWS documenta isso como "jitter completo" e mostra que reduz significativamente as colisões no lado do servidor em comparação com jitter igual ou sem jitter. max(0, ...)no reset — o timestamp de reset pode estar no passado no momento em que você faz o cálculo. Proteja-se contra um valor negativo de espera que cause o colapso do seu manipulador.
Erros comuns
Tratar erros não 429 como erros de limite de taxa. Um erro 503 é um erro do servidor. Um erro 401 significa que suas credenciais estão erradas. Verifique status_code == 429 explicitamente antes de aplicar lógica de tentativa de limite de taxa.
Aguardar silenciosamente o erro 429 e retornar dados vazios. Falhas silenciosas são mais difíceis de depurar do que exceções levantadas. Exponha o erro.
Usar um atraso fixo. Se você esgotou uma janela por hora com 47 minutos restantes no relógio, dormir 5 segundos não lhe traz benefício algum. Calcule com base no timestamp de reset.
Tentar indefinidamente. Defina um max_retries defina um limite e aumente após o esgotamento. Alguns 429s indicam esgotamento de quota que não se recuperará até o próximo período de faturamento — um loop de tentativa ilimitado é um erro.
Não monitorar ativamente X-RateLimit-Remaining. Se Remaining cair abaixo de 10% de Limit, comece a espacar as solicitações antes de atingir zero. A maioria dos SDKs não faz isso automaticamente. O custo é alguns milissegundos a mais de latência; o benefício é nunca ver um 429 no início.
Concluindo
O 429 não é um problema único que você corrige e esquece. É uma restrição recorrente, e ignorar os cabeçalhos que vêm com ele significa que você continuará enfrentando a mesma barreira. Use Retry-After quando a API o fornece. Calcule com base em X-RateLimit-Reset quando não o fornece. Adicione jitter para que as tentativas não se sincronizem. Defina um limite para evitar que loops de tentativa ilimitados se tornem incidentes em produção.
E quando você está olhando para X-RateLimit-Reset: 1716998400 e se perguntando quando isso realmente acontece — o Conversor de Timestamp Unix você saberá em um clique.
Instale nossas extensões
Adicione ferramentas de IO ao seu navegador favorito para acesso instantâneo e pesquisa mais rápida
恵 O placar chegou!
Placar é uma forma divertida de acompanhar seus jogos, todos os dados são armazenados em seu navegador. Mais recursos serão lançados em breve!
Ferramentas essenciais
Ver tudo Novas chegadas
Ver tudoAtualizar: Nosso ferramenta mais recente foi adicionado em 18 de junho de 2026
