Pourquoi cette erreur se produit-elle ?
L'API Google Ad Manager (GAM) impose des limites strictes sur le nombre de requêtes qu'un réseau ou qu'un identifiant utilisateur peut effectuer dans un intervalle de temps donné (généralement calculé par seconde et par minute). Lorsque vos scripts ou agents dépassent ce quota, l'API renvoie immédiatement une erreur QuotaError.EXCEEDED_QUOTA (en SOAP) ou un code HTTP 429 Too Many Requests (en REST).
Ces limites varient selon que vous utilisez un réseau Google Ad Manager Standard ou Google Ad Manager 360. Sur un réseau Standard, le quota de requêtes par seconde est très bas et peut facilement être saturé lors d'opérations de création groupée (bulk) ou de génération de rapports volumineux.
Attention aux requêtes concurrentes
Si vous exécutez plusieurs scripts ou instances d'application (comme plusieurs fonctions Cloud Run) en parallèle sur les mêmes identifiants de compte de service Google, les quotas sont partagés. C'est la cause la plus fréquente d'échecs intermittents en production.
Structure de l'erreur XML/SOAP
En SOAP, l'erreur est enveloppée dans un bloc SoapFault. Inspecter vos logs de débogage révélera généralement une structure similaire à celle-ci :
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<soap:Fault>
<faultcode>soap:Server</faultcode>
<faultstring>[QuotaError.EXCEEDED_QUOTA @ ]</faultstring>
<detail>
<ApiExceptionFault xmlns="https://www.google.com/apis/ads/publisher/v202605">
<message>[QuotaError.EXCEEDED_QUOTA @ ]</message>
<errors xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="QuotaError">
<fieldPath></fieldPath>
<trigger></trigger>
<errorString>QuotaError.EXCEEDED_QUOTA</errorString>
<reason>EXCEEDED_QUOTA</reason>
</errors>
</ApiExceptionFault>
</detail>
</soap:Fault>
</soap:Body>
</soap:Envelope> Comment résoudre l'erreur : L'algorithme de Backoff Exponentiel
La meilleure pratique de développement recommandée par Google consiste à intercepter cette erreur spécifique et à rejouer la requête après un certain délai d'attente. Ce délai doit augmenter de façon exponentielle à chaque échec successif pour éviter d'aggraver la saturation de l'API (un phénomène appelé retry storm).
Voici une implémentation propre en Python pour décorer vos appels de service GAM en utilisant une stratégie de retry avec Exponential Backoff et un facteur d'aléa (jitter) :
import time
import random
from googleads import errors
def execute_with_backoff(api_call_func, max_retries=5):
base_delay = 1.0 # délai de départ en secondes
for attempt in range(max_retries):
try:
return api_call_func()
except errors.GoogleAdsSoapResponseError as e:
# Vérification de la présence de QuotaError.EXCEEDED_QUOTA dans l'exception
is_quota_error = any(
getattr(error, 'reason', '') == 'EXCEEDED_QUOTA'
for error in e.detail.errors
)
if is_quota_error and attempt < max_retries - 1:
# Calcul de l'attente : base_delay * 2^attempt + jitter
delay = base_delay * (2 ** attempt) + random.uniform(0, 1.0)
print(f"Quota dépassé. Tentative {attempt + 1}/{max_retries}. Pause de {delay:.2f}s...")
time.sleep(delay)
continue
raise e # Si ce n'est pas une erreur de quota ou si retries épuisés, on lève l'erreur La limite du throttling local
Bien que le code ci-dessus fonctionne parfaitement pour un script s'exécutant sur un seul thread, il montre ses limites dans des architectures modernes distribuées. Si vous utilisez Google Cloud Run pour héberger votre plateforme AdOps ou si vous faites appel à des agents autonomes IA effectuant de multiples opérations simultanées, le throttling au niveau du processus individuel est insuffisant.
Lorsque 10 instances Cloud Run démarrent en même temps, elles ne communiquent pas leur état d'attente local. Elles continueront d'appeler l'API de Google de façon concurrente, provoquant un blocage persistant de votre réseau publicitaire. Pour résoudre ce problème, il est indispensable de centraliser l'acquisition de verrous (lock throttling) via une base de données transactionnelle ou un service de cache centralisé comme Redis.
