Les pubs vous déplaisent ? Aller Sans pub Auj.

Limitation d'API — En-têtes, retour exponentiel et résistance au code 429

Mis à jour le

Vous avez reçu un code 429. L'API vous indique de ralentir. Voici comment décoder les en-têtes X-RateLimit-*, comprendre Retry-After et mettre en œuvre un retour progressif avec un bruit pour que vos intégrations gèrent les limites de vitesse de manière fluide au lieu de frapper le serveur.

Limitation d'API — En-têtes, retour exponentiel et résistance au code 429 1
ANNONCE · Supprimer ?

Vous avez reçu un code 429. Peut-être que votre gestionnaire de webhook a planté. Peut-être que le batch a été silencieusement ignoré. L'API vous a renvoyé « Too Many Requests » et une série de headers de réponse que vous avez probablement balayés sans les lire.

Ces headers contiennent toute l'information nécessaire. Voici comment les lire, et comment écrire une logique de réessai qui ne pire pas la situation.

Les En-têtes qui Importent Vraiment

La plupart des API limitées par taux retournent une variante de ces en-têtes sur chaque réponse — pas seulement sur les codes 429 :

  • X-RateLimit-Limit — le nombre total de requêtes autorisées dans la fenêtre actuelle. L'API REST de GitHub donne aux utilisateurs authentifiés 5 000 requêtes par heure ; les requêtes non authentifiées sont limitées à 60.
  • X-RateLimit-Remaining — le nombre de requêtes restantes dans la fenêtre actuelle. Quand cette valeur atteint 0, la prochaine requête retourne un code 429.
  • X-RateLimit-Reset — le moment où la fenêtre se réinitialise, exprimé sous forme de timestamp Unix. C'est l'un des en-têtes que les développeurs ignorent le plus, et qui est le plus utile.
  • X-RateLimit-Used (spécifique à GitHub) — le nombre de requêtes consommées jusqu'à présent. Cela correspond à Limit - Remaining mais peut servir de vérification de cohérence.
  • Retry-After — apparaît uniquement dans les réponses 429. Soit une durée en secondes à attendre, soit une chaîne de date HTTP. Si l'API l'envoie, utilisez-la — elle est plus précise que tout ce que vous pourriez calculer vous-même.

Les en-têtes de réponse réels de GitHub ressemblent à ceci :

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

Le X-RateLimit-Resource l'entête est spécifique à GitHub : ils maintiennent des pools de quota séparés pour le REST, la recherche et GraphQL. L'utilisation de votre quota de recherche (limité à 30 requêtes par minute) ne touche pas votre quota principal — et vice versa.

Stripe est différent

Stripe ne utilise pas X-RateLimit-* le nommage. Ses en-têtes sont préfixées différemment :

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

Et dans le cas d'une réponse 429 :

Retry-After: 30

Le limiteur par défaut de Stripe est de 100 requêtes en mode live par seconde, et non par heure. Cela importe davantage que ce que l'on pourrait croire : une boucle importante 500 clients peut épuiser ce seuil en moins de 5 secondes si vous ne gérez pas le taux de requêtes sur votre côté.

Stripe distingue également entre les limites de taux de requêtes et les limites spécifiques aux ressources (par exemple, créer trop de clients en un court laps de temps). Le corps de la réponse 429 précise la limite qui a été dépassée — vérifiez toujours le corps complet, pas seulement le code de statut.

Décodage du timestamp de réinitialisation

Le X-RateLimit-Reset la valeur est un timestamp Unix. 1716998400 elle ne vous dit rien d'immédiat, mais elle est facile à décoder : utilisez la Convertisseur de timestamp Unix pour la convertir en date lisible UTC et voir exactement combien de temps il reste avant la réinitialisation.

Dans le code : reset_time - time.now() donne le nombre de secondes avant la réinitialisation. Mais vérifiez d'abord — si vous avez encore du quota, il n'y a rien à attendre. X-RateLimit-Remaining Ce que le corps de la réponse 429 vous dit

Le code de statut 429 seul n'est pas suffisant. Le corps de la réponse précise généralement la limite dépassée :

Stripe :

GitHub :

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

OpenAI va plus loin : le message d'erreur précise si vous avez dépassé une limite de tokens par minute ou une limite de requêtes par minute, ce qui modifie complètement votre stratégie de réessai. Enregistrez toujours le corps complet de la réponse 429.

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

Réessai exponentiel avec bruit

La solution naïve : capturer un 429, attendre 1 seconde, puis réessayer. Cette solution échoue pour deux raisons :

Si plusieurs workers tentent d'accéder à la même API, ils vont tous attendre 1 seconde et réessayer simultanément — une tempête de réessais synchronisés qui reproduit le problème.

  • 1 seconde est inutile si vous avez épuisé un quota horaire ou journalier. Vous allez simplement accumuler 3 600 nouvelles réponses 429.
  • L'approche correcte est un réessai exponentiel avec bruit : chaque tentative d'attente dure plus longtemps que la précédente, avec une composante aléatoire pour désynchroniser les workers simultanés.

L'ordre de priorité dans cette implémentation est intentionnel :

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 en premier

  • — si l'API vous indique exactement combien de temps attendre, utilisez-le. Ne calculez pas à la main. X-RateLimit-Reset en second lieu
  • — calculez le nombre de secondes avant la réinitialisation plutôt que de supposer un délai fixe. Bruit complet en dernier recours
  • répartit les tentatives de réessai sur l'ensemble de la fenêtre de réessai. Le blog d'architecture d'AWS décrit cela comme « bruit complet » et montre qu'il réduit mesurablement les collisions côté serveur par rapport au bruit égal ou à l'absence de bruit.random.uniform(0, cap) sur la réinitialisation
  • max(0, ...) — le timestamp de réinitialisation peut être dans le passé au moment où vous faites le calcul. Prévenez contre une valeur de somme négative qui ferait planter votre gestionnaire. Erreurs courantes

Traiter des erreurs non 429 comme des erreurs de taux.

Un code 503 est une erreur serveur. Un code 401 signifie que vos identifiants sont incorrects. Vérifiez avant d'appliquer une logique de réessai liée au taux. status_code == 429 Absorber le 429 et retourner des données vides.

Les échecs silencieux sont plus difficiles à déboguer que les exceptions levées. Montrez l'erreur. Utiliser un délai fixe.

Si vous avez épuisé un quota horaire avec 47 minutes restantes, attendre 5 secondes ne vous apporte rien. Calculez à partir du timestamp de réinitialisation. Réessayer indéfiniment.

limitez et augmentez après l'épuisement. Certains 429 indiquent une épuisement de quota qui ne se rétablira qu'au prochain cycle de facturation — un boucle de réessai illimitée est une erreur. Définir un max_retries Ne pas surveiller X-RateLimit-Remaining de manière proactive.

Si descend sous 10% de Remaining , commencez à espacer les requêtes avant d'atteindre zéro. La plupart des SDKs ne le font pas automatiquement. Le coût est quelques millisecondes de latence supplémentaires ; le bénéfice est de ne jamais voir un 429 au départ. LimitLe 429 n'est pas un problème ponctuel à corriger une fois pour toutes. C'est une contrainte récurrente, et ignorer les en-têtes qui l'accompagnent signifie que vous allez continuer à heurter la même limite. Utilisez

En résumé

lorsque l'API le fournit. Calculez à partir de Retry-After lorsqu'il n'est pas fourni. Ajoutez du bruit pour éviter que les tentatives de réessai ne soient synchronisées. Fixez une limite afin que les boucles de réessai illimitées ne deviennent pas des incidents en production. X-RateLimit-Reset Et quand vous regardez

et que vous vous demandez quand cela se produit réellement — le X-RateLimit-Reset: 1716998400 vous le dira en un clic. Convertisseur de timestamp Unix Limitation du taux API — En-têtes, Réessai exponentiel et Survie du 429 2

Envie d'une expérience sans pub ? Passez à la version sans pub

Installez nos extensions

Ajoutez des outils IO à votre navigateur préféré pour un accès instantané et une recherche plus rapide

Sur Extension Chrome Sur Extension de bord Sur Extension Firefox Sur Extension de l'opéra

Le Tableau de Bord Est Arrivé !

Tableau de Bord est une façon amusante de suivre vos jeux, toutes les données sont stockées dans votre navigateur. D'autres fonctionnalités arrivent bientôt !

ANNONCE · Supprimer ?
ANNONCE · Supprimer ?
ANNONCE · Supprimer ?

Coin des nouvelles avec points forts techniques

Impliquez-vous

Aidez-nous à continuer à fournir des outils gratuits et précieux

Offre-moi un café
ANNONCE · Supprimer ?