Frappe Framework
Limitation de débit (Rate Limiting)
limit et window se posent dans site_config.json. Les en-têtes X-RateLimit sont en microsecondes. user_based n’existe qu’à partir de la v17.
Fenêtre du site
Frappe limite les requêtes HTTP par fenêtre fixe, selon le temps qu’elles consomment, pas selon leur nombre. La somme des durées dans la fenêtre ne doit pas dépasser limit. Le compteur revient à 0 tous les window secondes, au début de chaque heure si window vaut 3600, dans le fuseau du site. Au-delà, la requête n’est pas traitée : HTTP 429.
{
"rate_limit": {
"limit": 600,
"window": 3600
}
}limit est le temps autorisé dans la fenêtre, en secondes. window est la taille de la fenêtre, en secondes.
Chaque réponse porte l’état. L’exemple sur https://frappe.io/docs montre X-RateLimit-Limit: 600000000 pour un plafond configuré de 600 secondes : les en-têtes de temps sont en microsecondes.
| En-tête | Unité | Sens |
|---|---|---|
| Retry-After | secondes | Temps avant la fin de la fenêtre, sur un 429 |
| X-RateLimit-Limit | microsecondes | Temps permis dans la fenêtre |
| X-RateLimit-Remaining | microsecondes | Temps encore disponible |
| X-RateLimit-Reset | secondes | Temps avant la remise à zéro |
| X-RateLimit-Used | microsecondes | Temps de traitement de la requête courante |
Une méthode
@rate_limit, dans frappe.rate_limiter, compte des appels sur une méthode en liste blanche.
| Argument | Défaut | Sens |
|---|---|---|
| key | None | Clé de frappe.form_dict pour distinguer la requête |
| limit | 5 | Nombre max, entier ou callable |
| seconds | 86400 | Fenêtre, 24 h par défaut |
| methods | ALL | Méthodes HTTP, une chaîne ou une liste |
| ip_based | True | Compte par adresse IP |
| endpoint | None | Nom de compteur, v17. Obligatoire si le callable n’a pas de chemin pointé stable, par exemple un functools.partial |
| user_based | False | Compte par identifiant de session, v17 |
Le suivi est soit réseau, soit utilisateur, jamais les deux. user_based=True ignore l’IP : les utilisateurs derrière un NAT ne se bloquent pas entre eux. ip_based=True et user_based=False est le comportement d’origine : seule l’IP compte. Un invité sur un point user_based retombe sur l’IP, pour qu’un invité ne vide pas un seau commun à tous les anonymes.
user_based ou endpoint en v15 ou v16 lève un TypeError. L’exemple, 10 appels par minute et par compte, avec repli invité par IP :
@frappe.whitelist()
@rate_limit(limit=10, seconds=60, user_based=True)
def generate_heavy_report():
passPoint d’attention
Le plafond du site est un temps, celui du décorateur est un nombre d’appels. Les en-têtes du site parlent en microsecondes alors que site_config.json parle en secondes.
