Bug #44730
Erreur SMS OVH : Too much requests. Please retry in 3 seconds.
0%
Description
On a cette nouvelle erreur de temps en temps :
error running send_job job (OVH error: {'status': 429, 'message': 'Too much requests.\nPlease retry in 3 seconds.\n'})
Question : est-ce que le passage en mode "jobs" provoque de nombreux appels simultanés vers OVH ? (envoi d'un seul coup de tous les SMS "jobbés") ?
Si oui, ça pourrait être la cause de ce problème et il faudrait trouver une parade.
Fichiers
Demandes liées
Révisions associées
Historique
Mis à jour par Nicolas Roche (absent jusqu'au 3 avril) il y a plus de 3 ans
- Assigné à mis à Nicolas Roche (absent jusqu'au 3 avril)
Mis à jour par Nicolas Roche (absent jusqu'au 3 avril) il y a plus de 3 ans
Question : est-ce que le passage en mode "jobs" provoque de nombreux appels simultanés vers OVH ?
Oui, les demandes sont différées pour être envoyées à la suites toutes les 5 minutes (sur le SaaS et idem à Toulouse) :
*/5 * * * * passerelle /usr/bin/passerelle-manage tenant_command cron --all-tenants jobsNos plus gros consommateurs de SMS sont :
- Toulouse : 2036 pages de jobs
- cd59 : 87 pages de jobs
- Mauguio : 66 pages de jobs
J'ai retrouvé le bug (à priori uniquement) sur Toulouse :
(je n'ai trouvé aucune information relative dans la doc d'OVH)
https://passerelle.eservices.toulouse-metropole.fr/ovh/sms/?page=15#logs
Le 2 juillet à 10:26:32 il y a un semblant de campagne de SMS pour dire aux usagers que la piscine n'est plus confinée :
https://passerelle.eservices.toulouse-metropole.fr/ovh/sms/?page=675#logs
Je pensais donc que ce message d'erreur était lié à cette utilisation exceptionnelle, mais en fait ce n'est pas un envoie si massif que ça : les envois ont duré jusqu'au 2 juillet à 11:17:25, soit 3375 envois en 50 minutes, ou encore 1.125 SMS par seconde.
Si oui, ça pourrait être la cause de ce problème et il faudrait trouver une parade.
Ici on voit que Toulouse et Maugio envoient des SMS en même temps (2 juillet 2020 à 11:16:56):
https://passerelle.eservices.toulouse-metropole.fr/ovh/sms/?page=11#logs
https://passerelle.demarches.mauguio-carnon.com/ovh/sms-via-ovh-eo/?page=6#logs
Résoudre le problème uniquement sur une instance n'est qu'un pis-aller, mais je peux proposer un patch dans ce sens si besoin.
Mis à jour par Benjamin Dauvergne il y a plus de 3 ans
Le souci il me semble c'est d'envoyer 1 par 1 ce qui est en fait un mailing, sachant que l'API supporte une liste de destinataires. Ce serait peut-être plus utile de bosser sur une sorte de dédoublonnage, avec une latence défini par l'appelant. Quand on poste un SMS, on peut définir qu'il reste en queue 5 minutes avant d'être envoyé, si un nouveau message avec le même contenu arrive, on l'ajoute aux destinataires du message existant et on ne crée rien de nouveau.
Mis à jour par Frédéric Péters il y a plus de 3 ans
Ici on voit que Toulouse et Maugio envoient des SMS en même temps (2 juillet 2020 à 11:16:56):
Pour info, Toulouse n'est pas sur le SaaS.
Mis à jour par Thomas Noël il y a plus de 3 ans
Nicolas Roche a écrit :
Oui, les demandes sont différées pour être envoyées à la suites toutes les 5 minutes
(sur le SaaS et idem à Toulouse) :
(...)
Je pensais donc que ce message d'erreur était lié à cette utilisation exceptionnelle,
mais en fait ce n'est pas un envoie si massif que ça : les envois ont duré jusqu'au 2
juillet à 11:17:25, soit 3375 envois en 50 minutes, ou encore 1.125 SMS par seconde.
Justement, 50 minutes = 10 envois en lot (chaque 5 minutes).
Donc il y a eu des salves de centaines d'envois d'un seul coup.
C'est ça qui est gênant avec le principe des jobs : ils provoquent des envois en masse.
(Je n'ai pas encore de solution, on est dans un soucis pas simple, pour les mails on a souvent le même soucis, comment "ralentir", et c'est de la configuration assez touchy dans les MTA)
Mis à jour par Nicolas Roche (absent jusqu'au 3 avril) il y a plus de 3 ans
si un nouveau message avec le même contenu arrive, on l'ajoute aux destinataires du message existant et on ne crée rien de nouveau.
Oui, en plus d'une latence défini par l'appelant, il faudrait fixer une limite raisonnable au nombre maximum de destinataires d'un message, pour dédoublonner les envois.
(Parce que j'imagine qu'il y a une limite au nombre de destinataires)
https://forum.ovh.com/showthread.php/111455-Envoi-de-SMS-en-masse-par-l-API-POST-ou-fichier
Question : est-ce que je relance les jobs en erreurs (à la main/souris) ?
Mis à jour par Thomas Noël il y a plus de 3 ans
- Lié à Development #44815: avoir la possibilité d'ajouter un job en lui demandant de s'exécuter tout de suite ajouté
Mis à jour par Nicolas Roche (absent jusqu'au 3 avril) il y a plus de 3 ans
ça pourrait se faire si l'envoi de SMS sortait une SkipJob dans ce cas...?
yep (c'est ce que j'ai compris)
https://dev.entrouvert.org/issues/21465#note-8
Mis à jour par Nicolas Roche (absent jusqu'au 3 avril) il y a plus de 3 ans
- Lié à Development #42230: Uniformiser les retours des connecteurs SMS ajouté
Mis à jour par Nicolas Roche (absent jusqu'au 3 avril) il y a plus de 2 ans
- Fichier 0001-ovh-retry-on-too-many-requests-error-44730.patch 0001-ovh-retry-on-too-many-requests-error-44730.patch ajouté
- Tracker changé de Support à Bug
- Statut changé de Nouveau à Solution proposée
- Patch proposed changé de Non à Oui
A défaut de pouvoir reproduire cette exception, OVH parle de code d'erreur API
https://docs.ovh.com/gb/en/sms/send_sms_messages_via_url_-_http2sms/#step-3-analyse-sent-messages
et donc je n'ai pas présagé qu'elle suivait la RFC.
https://datatracker.ietf.org/doc/html/rfc6585#section-4
Aussi, j'ai l'impression qu'elle n'a pas eu lieu avec la nouvelle API d'OVH et ne l'ai prise en compte que sur celle où elle a été vue.
Mis à jour par Nicolas Roche (absent jusqu'au 3 avril) il y a plus de 2 ans
- Fichier 0001-ovh-retry-on-too-many-requests-error-44730.patch 0001-ovh-retry-on-too-many-requests-error-44730.patch ajouté
J'ai ajouté le traitement de l'exception dans la vue qui permet à l'utilisateur de tester l'envoi d'un SMS,
où connector.send_msg()
y est appelé de manière synchrone.
Mis à jour par Thomas Noël il y a plus de 2 ans
En plus de tester le code 429, on pourrait vérifier qu'il y a un "Please retry" dans le message (ce qui va en plus "clarifier" la situation dans le code).
Mais surtout, si on cherche à envoyer 50 messages d'un coup, les repousser tous de 3 secondes ne va pas vraiment améliorer l'affaire (ça va re-coincer 3 secondes plus tard). Faire plutôt de l'aloha avec un « after_timestamp=random.randint(4,10) »
Mis à jour par Nicolas Roche (absent jusqu'au 3 avril) il y a plus de 2 ans
- Fichier 0001-ovh-retry-on-too-many-requests-error-44730.patch 0001-ovh-retry-on-too-many-requests-error-44730.patch ajouté
Fait.
Mis à jour par Benjamin Dauvergne il y a plus de 2 ans
Thomas Noël a écrit :
Mais surtout, si on cherche à envoyer 50 messages d'un coup, les repousser tous de 3 secondes ne va pas vraiment améliorer l'affaire (ça va re-coincer 3 secondes plus tard). Faire plutôt de l'aloha avec un « after_timestamp=random.randint(4,10) »
<superpedantman>Aloha ça utilise une distribution de poisson pas uniforme</superpedantman>.
https://git.entrouvert.org/authentic.git/tree/src/authentic2/utils/models.py#n25
Mis à jour par Nicolas Roche (absent jusqu'au 3 avril) il y a plus de 2 ans
Et pourtant...
https://docs.python.org/3/library/random.html#functions-for-integers
Changed in version 3.2: randrange() is more sophisticated about producing equally distributed values.
Mais c'est vrai qu'en testant j'ai vu beaucoup fois la borne max apparaître.
C'est quoi la bonne pratique, random.uniform(a, b) ?
Mis à jour par Nicolas Roche (absent jusqu'au 3 avril) il y a plus de 2 ans
Bon j'ai compris, tu me charries
>>> res = [0] * 11 >>> for i in range(0,100000): ... res[random.randint(4,10)] +=1 ... >>> res [0, 0, 0, 0, 14354, 14499, 14506, 14548, 14392, 14308, 14393] >>> res = [0] * 11 >>> for i in range(0,100): ... res[random.randint(4,10)] +=1 ... >>> res [0, 0, 0, 0, 17, 19, 18, 16, 5, 13, 12]
Mis à jour par Thomas Noël il y a plus de 2 ans
Je ne sais absolument pas de quoi vous parlez et quitte ce ticket sur la pointe de pieds.
Mis à jour par Benjamin Dauvergne il y a plus de 2 ans
Thomas Noël a écrit :
Je ne sais absolument pas de quoi vous parlez et quitte ce ticket sur la pointe de pieds.
Moi non plus je ne comprends plus; il est fort ce Nicolas.
Mis à jour par Nicolas Roche (absent jusqu'au 3 avril) il y a plus de 2 ans
http://www.enseignement.polytechnique.fr/informatique/profs/Georges.Gonthier/pi97/baccelli/proto.html
ALOHA: Dans ce protocole, un message qui vient de subir une collision doit attendre un temps tiré aléatoirement (et uniformément) sur l'intervalle entier avant une nouvelle tentative de retransmission. Ces variables aléatoires de retard sont supposées mutuellement indépendantes.
Reviens Thomas !
Mis à jour par Thomas Noël il y a plus de 2 ans
Il ne faut pas prendre tout ce qu'on dit au pied de la lettre. On se fout un peu de la répartition, je voulais juste dire qu'il faut éviter de tout envoyer 3 secondes plus tard, et randomiser un peu.
Mais after_timestamp=random.randint(4, 10)
ça ne va pas, il faut un timestamp -- et là je vois que c'est ce que j'avais proposé, et donc vraiment il ne faut pas prendre tout ce qu'on dit au pied de la lettre ;)
Mis à jour par Frédéric Péters il y a plus de 2 ans
il faut un timestamp
en fait le nom est resté mais ça peut prendre un nombre qui représentera le nombre de secondes,
def set_after_timestamp(self, value): if isinstance(value, datetime.datetime): self.after_timestamp = value elif isinstance(value, six.integer_types + (float,)): self.after_timestamp = timezone.now() + datetime.timedelta(seconds=value)
Mis à jour par Thomas Noël il y a plus de 2 ans
- Statut changé de Solution proposée à Solution validée
Frédéric Péters a écrit :
il faut un timestamp
en fait le nom est resté mais ça peut prendre un nombre qui représentera le nombre de secondes,
Même moi il ne faut pas que je prenne ce que dit mon cerveau au pied de la lettre ;)
Go !
Mis à jour par Benjamin Dauvergne il y a plus de 2 ans
Nicolas Roche a écrit :
http://www.enseignement.polytechnique.fr/informatique/profs/Georges.Gonthier/pi97/baccelli/proto.html
ALOHA: Dans ce protocole, un message qui vient de subir une collision doit attendre un temps tiré aléatoirement (et uniformément) sur l'intervalle entier avant une nouvelle tentative de retransmission. Ces variables aléatoires de retard sont supposées mutuellement indépendantes.
Le niveau d'enseignement a bien baissé à polytechnique : https://cs.stackexchange.com/questions/65206/the-throughput-of-the-aloha-protocol-if-the-binomial-distribution-was-used
Mis à jour par Nicolas Roche (absent jusqu'au 3 avril) il y a plus de 2 ans
- Statut changé de Solution validée à Résolu (à déployer)
commit a214de3d53533eefb7b8e2c710d1019eee238d01 (HEAD -> main) Author: Nicolas ROCHE <nroche@entrouvert.com> Date: Thu Sep 2 16:12:19 2021 +0200 ovh: retry on too many requests error (#44730)
Mis à jour par Frédéric Péters il y a plus de 2 ans
- Statut changé de Résolu (à déployer) à Solution déployée
ovh: retry on too many requests error (#44730)