web-dev-qa-db-fra.com

Devez-vous réessayer 500 erreurs API?

Mon équipe et moi nous intégrons à une société tierce et utilisons leur API pour effectuer différentes opérations CRUD. Leur API n'est cependant pas toujours fiable. Peut-être que 0,1% du temps, un appel API échoue simplement avec une erreur 500, puis lorsque vous essayez à nouveau, cela fonctionne correctement. Parfois, ils auront des moments où l'appel d'API échoue avec une erreur 500 plus de 90% du temps. Après ~ 10 tentatives, cela fonctionnera enfin. Elle dure généralement environ 4 heures et se produit tous les quelques mois. Nous avons vécu cela hier où 90% du temps l'appel de l'API échouait.

Le tiers nous a dit que nous devrions implémenter la logique de nouvelle tentative lors de la réception d'une erreur 500. Pour les opérations idempotentes, je pouvais voir que cela était utile. Cependant, pour les opérations non idempotentes, il semble que cela pourrait être dangereux. Par exemple, un appel API peut consister à envoyer un e-mail. Nous avons parfois remarqué que l'API pouvait renvoyer une erreur 500, même si l'e-mail avait été envoyé. Si je réessaye 10 fois l'appel de l'API, j'obtiens 10 500 erreurs, mais le destinataire peut toujours recevoir 10 e-mails. Cela pourrait être très mauvais.

Devrions-nous réellement ajouter une logique de nouvelle tentative pour 500 erreurs qui ne sont pas idempotentes?

Mes deux réflexions sur le moment où nous devrions ajouter réessayer:

  1. Lorsque nous sommes d'accord avec l'opération exécutée plusieurs fois
  2. Lorsque l'opération échoue est pire que l'opération réussie 10 fois (ou quelle que soit la limite de nouvelle tentative).

Je n'ai jamais eu à ajouter une logique de nouvelle tentative aux appels d'API car obtenir 500 erreurs est très mince. Est-il raisonnable de devoir le faire?

5
Eric

Cela se résume à ce qui est pire pour l'opération non idempotente spécifique:

  • lorsqu'il est exécuté plus d'une fois, ou

  • quand il est exécuté pas du tout.

Ce n'est pas une décision de conception technique, cela dépend du fonctionnement spécifique et des conséquences de telles défaillances dans le domaine.

En tant que mesure technique, vous pouvez vérifier s'il existe des options supplémentaires pour valider si une certaine opération s'est produite (au moins avec une certaine probabilité). Prenons l'exemple du courrier électronique: si l'API vous permet d'envoyer des demandes par courrier électronique avec une demande de copie aveugle incluse, vous pouvez utiliser cette fonction pour envoyer votre propre système comme une copie aveugle. Cela vous donne la possibilité d'implémenter un point de contrôle supplémentaire si l'e-mail d'origine a été envoyé ou non. Bien sûr, la copie aveugle peut ne pas atteindre votre système à temps en raison d'un décalage réseau, mais vous pouvez réduire la fréquence des opérations de messagerie en double via l'API.

Ou peut-être que l'API elle-même vous permettra d'inspecter un certain état ou des informations de journalisation pour certaines opérations. Bien que ces appels puissent également échouer, vous pouvez au moins réduire le taux d'échec à un degré acceptable en utilisant ces fonctionnalités.

En tant que principe d'ingénierie général: si vous avez un composant non fiable dans votre système, créez suffisamment de redondance pour rendre le système "suffisamment fiable".

7
Doc Brown

Déterminez si votre appel d'API est "au moins une fois", "au plus une fois" ou "exactement une fois" ( http://www.cs.unc.edu/~dewan/242/f97 /notes/ipc/node27.html ) en termes d'urgence. Pour au moins une fois, écrivez une logique de nouvelle tentative avec une sorte de coupure (par exemple, coupure exponentielle). Pour les autres cas, implémentez une meilleure surveillance et des alertes afin de savoir quand les choses tournent mal. Déplacez les opérations ayant échoué dans une file d'attente et implémentez une interface utilisateur qui vous permettra de sélectionner manuellement les opérations dans la file d'attente et de les exécuter.

6
sul4bh

En règle générale, oui. 5xx sont des "erreurs de serveur" et dans le monde des API REST c'est un phénomène courant. PAS aussi fréquent que votre cas, mais commun.

Par exemple. pour nos API hébergées dans AWS à l'aide d'API Gateways et Java Lambda throw 500/503/504 une fois tous les 2 jours en moyenne. Et généralement la première tentative se poursuit. Les problèmes sont des problèmes d'infrastructure transitoires, passerelle connectivité, lamba inaccessible, problèmes de réseau ...

TOUS REST doivent être retentés avec un délai exponentiellement croissant entre les tentatives pour les erreurs 5xx. Il existe des bibliothèques disponibles dans toutes les bibliothèques, ne pas utiliser pour les boucles.

L'idempotence complique bien sûr un peu les choses, mais je m'en tiendrai à la règle générale. Par exemple. 503, 504 signifie sûrement que vous pouvez réessayer. L'API doit apporter des garanties ou donner des conseils sur son comportement pendant 500s.

Bien sûr, j'appuie l'opinion des autres selon laquelle aucune API payante ne devrait être en panne pendant 4 heures .

2
Kashyap

En règle générale, 500 erreurs doivent être réessayées. Il existe une règle générale pour la plupart des codes d'erreur:

  • 2xx = Tout ce qui peut être fait a été fait.
  • 4xx = Vous (l'appelant) avez fait quelque chose de mal ou demandé quelque chose de non-sens.
  • 5xx = Nous (le serveur) avons fait quelque chose de mal.

Les erreurs 4xx se résument généralement à une demande qui est intrinsèquement mauvaise et ne peut pas être traitée. Les erreurs 5xx sont utilisées pour indiquer que le serveur a rencontré un problème privé, et rien n'indique que votre demande soit prouvée non valide.

Cela ne signifie pas que votre demande doit être valide. Par exemple, supposons que vous envoyez une demande pour récupérer un élément mais que vous utilisez un ID qui n'existe pas. Un serveur qui gère bien la demande vous donnera une réponse 404 (ou 204. J'ai entendu des arguments de toute façon et je pense que la distinction est contextuelle). Cependant, si le serveur a un bogue qui mène à une exception de référence nulle, vous obtiendrez probablement une réponse de 500.

En tant qu'appelant, lorsque vous obtenez une réponse 500, vous ne savez pas ce qui s'est passé. Tout ce que vous savez, c'est que le serveur ne vous a pas activement dit que votre demande était absurde. Ce qui signifie que vous ne pouvez pas supposer qu'il est inutile d'essayer de refaire la même demande.
Par exemple, vous avez peut-être reçu le 500 car la base de données du serveur était hors ligne. Si vous attendez un peu et réessayez, il peut réussir maintenant que la base de données est en ligne.

Mais lorsque vous recevez une erreur 4xx, le serveur a activement déclaré que votre demande n'est pas résolu et il n'y a aucun intérêt à réessayer.

C'est un peu une généralisation excessive, des exceptions marginales existent. Par exemple, le statut 429 (trop de demandes) signifie que vous (l'appelant) avez dépassé le nombre d'appels alloué, mais il est probable que votre même demande sera traitée correctement si vous attendez que d'autres demandes vous soient attribuées (par exemple, si vous atteignez le maximum quotidien, cela fonctionnera à nouveau demain).


Cependant, sul4bh a raison de dire que cela peut être contextuel et que certaines applications peuvent ne pas vouloir que vous envoyiez la même demande plusieurs fois.

Prenons par exemple une transaction bancaire. Vous envoyez la demande et obtenez un 500. Mais en réalité, le serveur a effectivement traité votre demande, mais il a rencontré un bug trivial dans le formatage du message de réponse.
Renvoyer votre demande peut être dangereux, car vous finirez par effectuer plusieurs transactions bancaires.

Cependant, je ne pense pas que ce soit à vous (l'appelant) de décider quand vous êtes autorisé à tirer la même demande et quand vous ne l'êtes pas. Il est de la responsabilité du serveur de communiquer clairement l'état réel des choses à l'appelant, et dans le scénario ci-dessus, il n'a pas réussi à le faire. Vous ne pouvez pas être tenu responsable d'avoir reçu de mauvaises informations et de répondre correctement aux informations fournies.

Si j'effectue un paiement via les services bancaires en ligne et que j'obtiens un 500 lorsque je soumets la transaction, je vais réessayer. C'est la réponse la plus sensible à une erreur 500. À cet effet, ma banque a effectivement mis en place un chèque. S'il constate que vous effectuez un deuxième virement en succession rapide pour le même montant et/ou vers le même compte, il vous indiquera qu'il a bien enregistré la première transaction.

Cela dépend donc beaucoup du serveur. On s'attend à ce qu'ils communiquent clairement avec vous, et lorsque vous supposez une communication claire, un 500 signifie que vous devez réessayer plus tard car la cause du problème était côté serveur, pas dans votre demande.
Si le serveur ne peut pas communiquer clairement, ou si le contexte de l’application exige que l’appelant préfère ne jamais effectuer deux fois la même action, les administrateurs du serveur doivent le communiquer clairement aux consommateurs de leur API et doivent faire des efforts raisonnables pour empêcher à tort de répéter deux fois la même action.

1
Flater