¿Odias los anuncios? Ir Sin publicidad Hoy

Límites de API — Encabezados, retroceso exponencial y sobrevivir al código 429

Actualizado en

Usted ha recibido un 429. La API le está indicando que debe reducir la velocidad. Aquí está cómo decodificar los encabezados X-RateLimit-*, comprender Retry-After y implementar un retraso exponencial con jitter para que sus integraciones manejen los límites de velocidad de forma adecuada en lugar de golpear al servidor.

Límite de tasas de API — Encabezados, reintentos exponenciales y superar el código 429 1
ANUNCIO · ¿ELIMINAR?

Usted recibió un 429. Tal vez su manejador de webhook se ha caído. Tal vez se ha descartado silenciosamente una tarea en lote. La API le dio «Demasiadas solicitudes» y una gran cantidad de encabezados de respuesta que probablemente ya ha pasado por alto.

Esos encabezados contienen toda la historia. Aquí cómo leerlos y cómo escribir lógica de reintentos que no empeoren el problema.

Los Encabezados que realmente importan

La mayoría de las APIs limitadas por tasas devuelven alguna variante de estos en cada respuesta, no solo en los casos de 429:

  • X-RateLimit-Limit — el número total de solicitudes permitidas en el intervalo actual. La API REST de GitHub permite a los usuarios autenticados 5.000 por hora; las solicitudes no autenticadas reciben 60.
  • X-RateLimit-Remaining — las solicitudes restantes en el intervalo actual. Cuando este valor llega a cero, la siguiente solicitud devuelve un 429.
  • X-RateLimit-Reset — el momento en que se reinicia el intervalo, expresado como un timestamp en formato Unix. Este es el encabezado que más se ignora y el más útil.
  • X-RateLimit-Used (específico de GitHub) — solicitudes consumidas hasta ahora. Es un reflejo de Limit - Remaining pero útil para comprobaciones de validez.
  • Retry-After — solo aparece en respuestas de 429. Puede ser un número de segundos para esperar o una cadena de fecha HTTP. Si la API lo incluye, úsalo: es más preciso que cualquier cálculo que hagas tú mismo.

Los encabezados reales de respuesta de GitHub se ven así:

X-RateLimit-Limit: 5000
X-RateLimit-Remaining: 4823
X-RateLimit-Reset: 1716998400
X-RateLimit-Used: 177
X-RateLimit-Resource: core

El X-RateLimit-Resource el encabezado es específico de GitHub: mantienen conjuntos separados de cuotas para REST, búsqueda y GraphQL. Usar tu cuota de búsqueda (limitada a 30 solicitudes por minuto) no afecta tu cuota principal — y viceversa.

Stripe es diferente

Stripe no utiliza X-RateLimit-* nomenclatura. Sus encabezados tienen un prefijo diferente:

Stripe-Ratelimit-Limit: 100
Stripe-Ratelimit-Remaining: 97
Stripe-Ratelimit-Reset: 1716998460

Y en un caso de 429:

Retry-After: 30

La limitación predeterminada de Stripe es de 100 solicitudes en modo activo por segundo, no por hora. Esto importa más de lo que parece: un bucle que importa a 500 clientes puede agotar ese límite en menos de 5 segundos si no se limita en tu lado.

Stripe también distingue entre límites de tasas de solicitud y límites específicos de recursos (por ejemplo, crear demasiados clientes en un breve periodo). El cuerpo de la respuesta 429 especifica cuál límite has superado — siempre registra el cuerpo completo, no solo el código de estado.

Decodificación del timestamp de reinicio

El X-RateLimit-Reset el valor es un timestamp en formato Unix. 1716998400 no te dice nada de inmediato, pero es fácil decodificarlo: usa la Convertidor de marcas de tiempo de Unix para convertirlo a una fecha legible en UTC y ver exactamente cuánto tiempo queda hasta el reinicio.

En código: reset_time - time.now() da los segundos hasta que se reinicia el intervalo. Pero verifica primero — si aún tienes cuota, no hay nada que esperar. X-RateLimit-Remaining Qué información proporciona el cuerpo de la respuesta 429

El código de estado 429 por sí solo no es suficiente. El cuerpo de la respuesta normalmente especifica cuál límite se ha superado:

Stripe:

GitHub:

{
  "message": "API rate limit exceeded for user ID 12345.",
  "documentation_url": "https://docs.github.com/rest/overview/rate-limits"
}

OpenAI avanza más: el mensaje de error especifica si has superado un límite de tokens por minuto o un límite de solicitudes por minuto, lo que cambia completamente tu estrategia de reintentos. Registra siempre el cuerpo completo de la respuesta 429.

{
  "error": {
    "code": "rate_limit",
    "message": "Too many requests hit the API too quickly.",
    "type": "invalid_request_error"
  }
}

Retorno exponencial con ruido

La solución básica: captura un 429, espera 1 segundo y vuelve a intentarlo. Esto falla por dos razones:

Si tienes varios trabajadores que acceden al mismo punto final, todos esperarán 1 segundo y volverán a intentar simultáneamente — una tormenta de reintentos sincronizados que recrea el problema.

  • 1 segundo es inútil si has agotado un límite por hora o por día. Solo acumularás 3.600 más 429s.
  • La solución correcta es el reintentos exponencial con ruido: cada intento espera más tiempo que el anterior, con un componente aleatorio para desincronizar los trabajadores concurrentes.

El orden de prioridad en esta implementación es deliberado:

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")

Retry-After primero

  • — si la API te dice exactamente cuánto tiempo esperar, úsalo. No intentes calcularlo tú mismo. X-RateLimit-Reset como respaldo
  • — calcula los segundos hasta el reinicio en lugar de adivinar un retraso fijo. Ruido completo como último recurso
  • distribuye los reintentos a través del intervalo completo de espera. El blog de arquitectura de AWS documenta esto como “ruido completo” y muestra que reduce significativamente las colisiones en el lado del servidor en comparación con el ruido igual o sin ruido en absoluto.random.uniform(0, cap) en el reinicio
  • max(0, ...) — el timestamp de reinicio puede estar en el pasado cuando lo calcules. Protege contra un valor de espera negativo que cause un error en tu manejador. Errores comunes

Tratar errores no 429 como errores de tasa.

Un 503 es un error del servidor. Un 401 significa que tus credenciales son incorrectas. Verifica explicitamente antes de aplicar lógica de reintentos por límite de tasa. status_code == 429 Atrapar el 429 y devolver datos vacíos.

Los fallos silenciosos son más difíciles de depurar que las excepciones lanzadas. Muestra el error. Usar un retraso fijo.

Si has agotado un intervalo por hora y quedan 47 minutos en el reloj, esperar 5 segundos no te ayuda en absoluto. Calcula desde el timestamp de reinicio. Reintentar indefinidamente.

limita y eleva después de que se agote. Algunos 429 indican agotamiento de cuota que no se recuperará hasta el próximo período de facturación — un bucle de reintentos ilimitado es un error. Establecer un max_retries No monitorear proactivamente X-RateLimit-Remaining.

Si cae por debajo de 10% de Remaining , comienza a espaciarte las solicitudes antes de que llegue a cero. La mayoría de los SDKs no lo hacen automáticamente. El costo es unos milisegundos extra de latencia; el beneficio es nunca ver un 429 en primer lugar. LimitEl 429 no es un problema único que se resuelve y se olvida. Es una restricción recurrente, y ignorar los encabezados que lo acompañan significa que seguirás chocando contra la misma pared. Usa

Conclusión

cuando la API lo proporciona. Calcula desde Retry-After cuando no lo hace. Añade ruido para que los reintentos no se sincronicen. Establece un límite para evitar que los bucles de reintentos ilimitados se conviertan en incidentes en producción. X-RateLimit-Reset Y cuando estás mirando

y te preguntas cuándo realmente es — el X-RateLimit-Reset: 1716998400 te dirá en un clic. Convertidor de marcas de tiempo de Unix Limitación de tasas de API — Encabezados, reintentos exponenciales y supervivencia del 429 2

¿Quieres eliminar publicidad? Adiós publicidad hoy

Instalar extensiones

Agregue herramientas IO a su navegador favorito para obtener acceso instantáneo y búsquedas más rápidas

añadir Extensión de Chrome añadir Extensión de borde añadir Extensión de Firefox añadir Extensión de Opera

¡El marcador ha llegado!

Marcador es una forma divertida de llevar un registro de tus juegos, todos los datos se almacenan en tu navegador. ¡Próximamente habrá más funciones!

ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?
ANUNCIO · ¿ELIMINAR?

Noticias Aspectos técnicos clave

Involucrarse

Ayúdanos a seguir brindando valiosas herramientas gratuitas

Invítame a un café
ANUNCIO · ¿ELIMINAR?