Anúncios incomodam? Ir Sem anúncios Hoje

Limitação de Taxa da API — Cabeçalhos, Retorno Exponencial e Sobrevivência ao Código 429

Atualizado em

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.

Limitação de taxa da API — Cabeçalhos, Retentativa Exponencial e Sobrevivência ao 429 1
ANUNCIADO Remover?

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 - Remaining mas ú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 recursorandom.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.

Quer eliminar anúncios? Fique sem anúncios hoje mesmo

Instale nossas extensões

Adicione ferramentas de IO ao seu navegador favorito para acesso instantâneo e pesquisa mais rápida

Ao Extensão do Chrome Ao Extensão de Borda Ao Extensão Firefox Ao Extensão Opera

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!

ANUNCIADO Remover?
ANUNCIADO Remover?
ANUNCIADO Remover?

Notícias com destaques técnicos

Envolver-se

Ajude-nos a continuar fornecendo ferramentas gratuitas valiosas

Compre-me um café
ANUNCIADO Remover?