Ressources

Limitation de débit des requêtes

Limiter le nombre d'appels à une méthode sur une période, par adresse IP, par clé ou par utilisateur connecté, avec le décorateur @rate_limit.

Limitation de débit des requêtes

Le décorateur rate_limit limite le nombre d'appels à une méthode pendant une période donnée. Au-delà de la limite, Dodock refuse l'appel et répond par une erreur HTTP 429. Il sert surtout à protéger les méthodes ouvertes aux invités (formulaires, envoi d'e-mails, inscriptions) contre les abus.

Ce décorateur compte les appels sur une période. Pour limiter les exécutions simultanées d'une méthode lente, voir Limitation de concurrence.

Utiliser le décorateur

Importez rate_limit depuis frappe.rate_limiter et placez-le au-dessus de la fonction, sous @frappe.whitelist() :

import frappe
from frappe.rate_limiter import rate_limit


@frappe.whitelist()
@rate_limit(limit=10, seconds=60, user_based=True)
def demander_un_devis(produit: str):
    ...

Exemple fictif : avec ces valeurs, un utilisateur connecté peut appeler demander_un_devis 10 fois par minute. Son 11e appel dans la même minute est refusé, quelle que soit l'adresse IP d'où il se connecte. Les autres utilisateurs de la même adresse IP ne sont pas affectés.

Paramètres

ParamètreTypeDéfautDescription
keystr | NoneNoneNom d'un paramètre de la requête (frappe.form_dict). Sa valeur sépare les compteurs : chaque valeur a son propre compteur.
limitint | Callable5Nombre maximal d'appels pendant la période. Une fonction sans argument est appelée à chaque requête pour obtenir la valeur.
secondsint86400 (24 h)Durée de la période, en secondes.
methodsstr | list"ALL"Méthodes HTTP concernées. Avec ALL, toutes les méthodes sont limitées.
ip_basedboolTrueIdentifie l'appelant par son adresse IP.
user_basedboolFalseIdentifie un utilisateur connecté par son compte.
endpointstr | NoneNoneNom du compteur. Obligatoire quand la fonction décorée n'a pas de chemin pointé stable, par exemple une functools.partial. Par défaut : <module>.<nom de la fonction>.

Identifier l'appelant

Dodock compte les appels par « identité ». Elle dépend de user_based, de ip_based et de key.

Avec user_based=True

L'identité est choisie dans cet ordre :

  1. L'utilisateur connecté, s'il n'est pas Guest. Ce choix prime sur l'adresse IP : un même utilisateur partage un seul compteur sur toutes ses adresses IP, et deux utilisateurs derrière la même adresse IP (réseau d'entreprise, NAT) ont chacun le leur.
  2. Pour un invité (Guest) avec ip_based=True, son adresse IP.
  3. Pour un invité avec ip_based=False, son adresse IP quand elle est connue. Sinon, une identité commune Guest.

L'identité d'un invité reste donc l'adresse IP, même avec ip_based=False. Les invités ne partagent pas un compteur global.

Si key est défini et que la requête contient une valeur pour ce paramètre, cette valeur est ajoutée à l'identité. Un même utilisateur a alors un compteur par valeur.

Avec user_based=False

keyip_basedIdentité
définiTrueadresse IP et valeur de la clé
non définiTrueadresse IP
définiFalsevaleur de la clé
non définiFalseaucune : erreur (voir ci-dessous)

Comportement

  • Le décorateur ne s'applique que pendant une requête HTTP. Hors requête (tâches en arrière-plan, commandes bench, appel direct dans un script), la fonction s'exécute sans limite. Il ne s'applique pas non plus aux méthodes HTTP absentes de methods.
  • Les compteurs sont stockés dans le cache Redis. La clé a la forme <base du site>|rl:<compteur>:<identité>:<secondes> : le préfixe du site sépare les compteurs de chaque site d'un même bench. La période démarre au premier appel suivant l'expiration du compteur.
  • Quand la limite est dépassée, Dodock lève frappe.RateLimitExceededError, qui répond en HTTP 429 avec le message « Vous avez atteint la limite de requêtes. Veuillez réessayer dans quelques secondes. »
  • Les compteurs de deux fonctions différentes sont indépendants, sauf si vous leur donnez le même endpoint.

Erreur « Une clé, un indicateur IP ou un indicateur utilisateur est requis. »

Si aucune identité n'est disponible, Dodock lève une frappe.ValidationError avec ce message. Cela arrive quand ip_based=False et user_based=False, sans key, ou avec un key dont la requête ne contient pas de valeur. Avec ip_based=True, l'adresse IP suffit et une valeur de clé absente ne provoque pas d'erreur. Réactivez ip_based ou user_based, ou envoyez la valeur de la clé.

Points d'attention

  • Sans user_based, tous les utilisateurs d'un même réseau partagent le compteur de leur adresse IP. Une méthode utilisée par des utilisateurs connectés depuis un réseau partagé doit utiliser user_based=True.
  • Derrière un proxy inverse, l'adresse IP lue par Dodock doit être celle du client. Sinon, tous les invités partagent la même adresse.