Lisser ses appels avec le rate limiting
L'API publique CaptainDNS applique deux étages de rate limiting : un par IP source en amont de l'authentification, et un token bucket par clé avec capacité alignée sur le plan. Ce guide explique comment chaque étage fonctionne et comment écrire un client qui respecte les limites sans perdre d'appels.
Deux étages de protection
1. Rate limit par IP pré-auth
Avant même de lire le header Authorization, un limiteur borne le trafic par IP source. La valeur par défaut est 120 requêtes par minute par IP. Cet étage protège contre les attaques volumétriques et le credential stuffing.
Un dépassement retourne 429 RATE_LIMITED avec Retry-After: 60. Aucune clé n'est vérifiée, aucun crédit n'est consommé.
2. Token bucket par clé
Une fois la clé authentifiée, un token bucket persistant gère la limite par clé. La capacité est alignée sur le plan associé à la clé :
| Plan | Capacité (jetons) | Recharge |
|---|---|---|
| Free | 10 | 10 jetons/min |
| Starter | 60 | 60 jetons/min |
| Pro | 500 | 500 jetons/min |
| Business | 1 000 | 1 000 jetons/min |
| Enterprise | 1 200 | 1 200 jetons/min |
Chaque requête authentifiée consomme un jeton. Le bucket se remplit de manière continue (recharge fractionnaire), donc vous n'avez pas besoin d'attendre un tick d'une minute pleine avant de pouvoir réessayer.
Un bucket vide retourne 429 RATE_LIMITED. Le header Retry-After contient le nombre de secondes avant que le prochain jeton soit disponible.
Headers de réponse
Chaque réponse contient ces headers standard :
RateLimit-Policy: "default";q=60;w=60
RateLimit: limit=60, remaining=58, reset=42
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1717200000
RateLimit-Policy: format IETF draft, décrit la politique.qest la capacité,wla fenêtre en secondes.RateLimit: format IETF draft, état courant.remainingjetons disponibles,resetsecondes avant recharge complète.X-RateLimit-Limit/Remaining/Reset: même info au format X-headers pour compatibilité avec les clients existants.
Sur un 429, vous aurez en plus :
Retry-After: 12
Le client doit respecter cette valeur et attendre le nombre de secondes indiqué avant de réessayer.
Stratégie de retry recommandée
Le pattern idiomatique pour un client respectueux est le backoff exponentiel borné :
- À chaque réponse, lisez
X-RateLimit-Remaining. Si le ratioremaining / limitest inférieur à 20 %, ralentissez préventivement. - Sur
429 RATE_LIMITED, lisezRetry-After. Attendez cette durée au minimum. - Si vous empilez plusieurs 429 consécutifs, appliquez un multiplicateur : 2x, 4x, 8x avec un plafond à 60 secondes.
- Ajoutez un jitter aléatoire de +/- 20 % pour éviter que plusieurs clients retentent en simultané.
- Limitez le nombre total de retries (ex : 5). Au-delà, journalisez en erreur et remontez dans votre observabilité.
Exemple de pseudo-code :
delay = retryAfter + random(-0.2, 0.2) * retryAfter
for attempt in 1..5:
response = send(request)
if response.status != 429:
return response
retryAfter = response.header["Retry-After"] or delay * attempt
sleep(min(retryAfter, 60))
raise RateLimitExceeded
Strategies spécifiques aux pipelines batch
Les intégrations qui traitent un grand volume en batch (ex : scan de 10 000 domaines chaque nuit) bénéficient de stratégies différentes :
- Token bucket côté client : répliquez localement le bucket serveur et ne lancez une requête que si un jeton est disponible. Cela évite les 429 et le jitter.
- Paralléliser en fonction de la capacité : un plan Pro a 500 jetons/min, soit environ 8 requêtes par seconde. Paralléliser à 8 workers maximum est plus efficace qu'un unique worker qui fait 500 itérations par minute avec des pauses.
- Découpage par endpoint coûteux : si vous faites 500
page-crawl-check(10 crédits) et 500dmarc/lookup(1 crédit), répartissez-les dans deux files distinctes pour lisser la consommation de crédits et respecter plus facilement le rate limit. - Fenêtres de maintenance : certains batchs peuvent tourner hors heures de pointe pour éviter de saturer l'enveloppe en compétition avec le trafic realtime.
Ce qui compte comme une requête
Chaque requête HTTP authentifiée compte pour un jeton, même si elle échoue en 400 ou en 500. Le rate limit protège le backend ; la validation d'input est appliquée après l'obtention d'un jeton.
Exceptions :
429 RATE_LIMITED: évidemment ne consomme pas de jeton, puisque le bucket est vide.401 INVALID_API_KEY: ne touche pas au bucket par clé (on ne sait pas encore quelle clé). En revanche, le rate limit par IP compte.403 IP_NOT_ALLOWED: ne consomme ni jeton ni crédit, car la vérification est faite avant la consommation.
Augmenter sa capacite
La capacité du token bucket est une propriété du plan, pas un paramètre de la clé. Pour augmenter la capacité :
- Passez au plan supérieur depuis le dashboard CaptainDNS.
- L'effet est immédiat : la clé hérite du nouveau plafond dès la prochaine requête.
Les clients Enterprise peuvent négocier un plafond custom (jusqu'à 5 000 req/min sur devis) avec leur account manager CaptainDNS.
Diagnostiquer un 429
Un 429 inattendu peut avoir plusieurs causes :
- Bucket pré-auth : vous dépassez 120 req/min sur une seule IP. Vérifiez que plusieurs services ne partagent pas la même IP de sortie (NAT, CGNAT).
- Token bucket par clé : votre plan n'offre pas la capacité nécessaire. Passez à un plan supérieur ou réduisez la concurrence.
- Pic ponctuel : un batch non lissé a émis 200 requêtes en une seconde. Ajoutez du jitter et un lissage côté client.
- Drift d'horloge : dans les rares cas où votre serveur est désynchronisé avec NTP, le header
Retry-Afterpeut sembler excessif. Synchronisez votre horloge.
Si le problème persiste malgre un respect scrupuleux de Retry-After, ouvrez un ticket support avec le X-Request-Id d'une requête 429 representative.
Outils CaptainDNS liés
- Le DNS lookup permet de vérifier manuellement un enregistrement sans consommer de credit.
- Le DMARC monitoring aggrege les rapports DMARC sans passer par l'API publique.
Passez ensuite à l'idempotence pour économiser crédits et jetons sur les retries, ou aux codes d'erreur pour identifier les 429 vs les autres rejets.