Skip to content

API particulier : Respecter la fréquence d’appels et les workers web#4983

Merged
francoisfreitag merged 1 commit intomasterfrom
ff/rate-limits
Nov 5, 2024
Merged

API particulier : Respecter la fréquence d’appels et les workers web#4983
francoisfreitag merged 1 commit intomasterfrom
ff/rate-limits

Conversation

@francoisfreitag
Copy link
Member

🤔 Pourquoi ?

Être un bon citoyen, éviter de tabasser l’API des copains.
Éviter de faire attendre des workers web, car on peut vite saturer notre bande passante (DoS). Par exemple, si l’API se met à répondre avec des 500, chaque worker qui essaye de certifier un critère sera bloqué pour 3 * 2 = 6s, à attendre et réessayer. En augmentant le nombre de critères certifiés, on peut assez vite faire tomber le service, où tous les workers sont en train de time.sleep(2) (les fainéants !).

🍰 Comment ?

Suivre les indications de l’API quant à la fréquence des appels.
Ne faire que le premier essai de certification en synchrone. En cas d’échec, démarrer une tâche asynchrone qui effectuera la vérification.

@francoisfreitag francoisfreitag added the modifié Modifié dans le changelog. label Oct 24, 2024
@francoisfreitag francoisfreitag self-assigned this Oct 24, 2024
@francoisfreitag francoisfreitag marked this pull request as draft October 25, 2024 05:35
@francoisfreitag francoisfreitag marked this pull request as ready for review October 25, 2024 07:12
certify_criteria(self)
except httpx.HTTPError:
logger.info("Could not certify criteria synchronously.", exc_info=True)
async_certify_criteria(self._meta.model_name, self.pk)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Toute autre erreur (y compris d'autres exceptions de httpx qui ne sont pas sous HTTPError) va casser et faire échouer la transition accept. Est-ce vraiment souhaité ?

Est-ce que l'on ne rajouterait pas un except générique avec un logger.exception pour fail safe mais quand même avoir une trace ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Toutes les exceptions de httpx héritent de HTTPError: https://www.python-httpx.org/exceptions/

On peut effectivement laisser un except générique pour être sûrs de ne pas bloquer une embauche pour un problème d’intégration partenaire externe (genre format de réponse de l’API qui a changé). 👍
On doit pouvoir laisser au niveau info, car on va réessayer, et l’erreur remontera à ce moment là ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Est-ce pertinent de réessayer pour ces cas de figure ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Démarrer une tâche asynchrone pour réessayer me semble pertinent : une erreur réseau devrait être résolue et l’app devrait pouvoir interroger l’API particulier au prochain essai.

Pour la politique de ré-essai côté tâche asynchrone, j’ai fait un truc assez simple. À voir si on complexifie.

@francoisfreitag francoisfreitag force-pushed the ff/rate-limits branch 3 times, most recently from 58d8db6 to 0be3bbf Compare October 29, 2024 12:13
@leo-naeka leo-naeka self-requested a review October 30, 2024 08:55
@francoisfreitag francoisfreitag force-pushed the ff/rate-limits branch 10 times, most recently from 214ab46 to 0a544d5 Compare October 31, 2024 15:17
data = api_particulier.revenu_solidarite_active(client, job_seeker)
except httpx.HTTPStatusError as exc:
criterion.data_returned_by_api = exc.response.json()
logger.error("%d: %s", exc.response.status_code, criterion.data_returned_by_api)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Est-ce qu'on ne voudrait pas un peu plus de contexte dans ces logs ?

Copy link
Member Author

@francoisfreitag francoisfreitag Nov 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Genre la PK du diag/critère d’éligibilité ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oui avec un peu de texte genre Error certifying criterion=Model[123] - code=500 data={} et éviter des lignes de logs du genre 500: {} 😅

@francoisfreitag francoisfreitag force-pushed the ff/rate-limits branch 2 times, most recently from 9c2dd0f to 0ef3ed9 Compare November 4, 2024 10:39
# The data provider for API particulier returned a 429.
# Re-raising will cause huey to retry after a long retry_delay,
# let’s hope the data provider rate limit has been reset by then.
raise
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ne pourrait-on pas considérer qu'il s'agit d'une 429 sous couverture et lever une RetryTask également ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Si, tout à fait. Le problème est de savoir quand retry, car l’API ne nous communique pas les instructions du fournisseur de données. Du reste, si j’ai bien compris, le fournisseur de données ne communique pas non plus ses instructions ré-essai. 🙈

Dans le doute, je me suis dit qu’on pouvait laisser le mécanisme générique (attendre 10 minutes) entrer en jeu.

On peut aussi RetryTask qui a l’avantage de ne pas changer le nombre de retry de la tâche, et est peut-être plus clair. On peut fixer le délai à 10 minutes pour le moment, et on le fera évoluer si besoin. 👍

Copy link
Contributor

@celine-m-s celine-m-s left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉
image

Move API calls to an async task, to avoid holding up web workers with
sleep. Having tenacity retry during the request/response cycle was very
risky, as a few concurrent certifications with errors (e.g. downtime on
the API) could bring down all workers for multiple seconds.

Implement a retry policy based on indications from the API.

`test_service_unavailable` was updated to use a payload matching what
the API actually returns and not what the OpenAPI specification
describes.
@francoisfreitag
Copy link
Member Author

francoisfreitag commented Nov 4, 2024

J’ai ajouté du contexte au message de log, et fait une RetryTask(delay=3600) quand on se prend une 503 parce que le fournisseur de données rate-limit l’API particuliers.

@francoisfreitag francoisfreitag added this pull request to the merge queue Nov 5, 2024
Merged via the queue into master with commit 58b2c19 Nov 5, 2024
@francoisfreitag francoisfreitag deleted the ff/rate-limits branch November 5, 2024 08:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug modifié Modifié dans le changelog.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants