Quelles sont les meilleures pratiques pour gérer les erreurs dans les actions en plusieurs étapes entre le client et les serveurs ?

Aug 18 2020

J'ai un site Web qui télécharge des offres d'emploi sur mon API, il y a plusieurs étapes à suivre :

  1. Téléchargez une image de logo sur le stockage de fichiers.

  2. Insérez des données sur l'offre d'emploi dans une base de données.

  3. Traiter un paiement avec un fournisseur tiers.

  4. Envoyez un e-mail via un fournisseur tiers.

En général, vous pouvez imaginer que d'autres étapes sont présentes ici dans différentes applications, par exemple obtenir des informations d'une API tierce, valider un ReCAPTCHA, mettre à jour l'API d'indexation Google, envoyer un SMS, etc., etc.

Étant donné que tous ces éléments utilisent des tiers et sont indépendants du serveur qui gère l'appel d'API, l'un d'entre eux peut échouer à laisser certaines des étapes terminées avec succès et d'autres non (par exemple, logo mis à jour mais paiement non collecté).

Ma question est la suivante : comment les erreurs dans ces types d'actions en plusieurs étapes entre les clients et les serveurs sont-elles généralement gérées dans les systèmes de production ? Existe-t-il des normes ou des pratiques exemplaires acceptées?


J'ai considéré :

  1. Ne pas gérer les erreurs et espérer que tout se passe sans erreur.

  2. Définir une fonction "annuler" sur le backend pour chacune des étapes et si l'une des étapes échoue, puis l'appeler sur les étapes précédentes. Avec des actions composées de nombreuses étapes, cela pourrait se transformer en code spaghetti assez rapidement, et certaines étapes ne peuvent pas être annulées aussi facilement - par exemple l'envoi d'un e-mail.

  3. Créer un point de terminaison distinct sur le backend pour chacune des étapes et laisser le client appeler chacune à son tour. Cela pourrait également utiliser un point de terminaison d'API "annuler". Ainsi, si le client reçoit une erreur sur l'une des étapes, il peut alors annuler toutes les étapes précédentes. Cela a l'avantage de permettre au client d'estimer la progression de l'action en cours d'exécution, c'est-à-dire qu'il pourrait afficher « 1 des 5 étapes terminées » à l'utilisateur.

  4. Créer une ligne dans une base de données (ou une base de données en mémoire ?) Pour chaque action et lorsque chaque étape est terminée, marquer la colonne correspondante comme terminée. Lorsque chaque colonne de la ligne est terminée, renvoyez une réponse à l'utilisateur.

Réponses

1 RalfKleberhoff Aug 19 2020 at 13:30

Ce processus en plusieurs étapes est une transaction, passant d'un état initial cohérent ("rien ne s'est passé") à un état final ("offre d'emploi terminée"), avec des étapes intermédiaires qui laissent votre application dans un état (éventuellement) incohérent.

Vous ne devez pas déléguer la gestion des transactions à votre client, surtout ne pas diviser le processus en appels individuels (sinon il sautera peut-être l'étape de paiement - mauvais pour l'entreprise).

Si une étape échoue, c'est sûrement un non-sens de continuer, vous devez faire une sorte de retour à un état acceptable, pas nécessairement l'état initial. Par exemple, je ne vois pas la nécessité absolue de supprimer l'image téléchargée du stockage de fichiers.

Tout d'abord, j'essaierais d'organiser les étapes de manière à ce que la plupart des étapes intermédiaires soient acceptables, il n'est donc pas nécessaire de revenir en arrière.

Les étapes délicates sont sûrement le paiement et le courrier électronique (si je comprends bien votre entreprise).

  • Facturer le client sans avoir les e-mails envoyés est mauvais (proche de la fraude).
  • Envoyer les e-mails sans recevoir le paiement signifie perdre de l'argent (si cela n'arrive pas souvent, cela peut être tolérable). Vous ne pouvez certainement pas annuler les e-mails une fois qu'ils ont été envoyés, mais vous pouvez peut-être annuler les paiements (à moins que vous ne perdiez la connexion avec le fournisseur juste à ce moment-là).

Comme vous comptez sur des connexions externes, je ne vois aucun moyen d'éviter absolument l'achèvement partiel de votre transaction, donc je concevrais le processus de telle manière que les échecs intermédiaires

  • soit hautement improbable
  • ou laisser un état tolérable.

Alors, je ferais

  1. Envoyez un ping à tous les services externes pour vous assurer qu'ils sont actuellement opérationnels et joignables
  2. Téléchargez une image de logo sur le stockage de fichiers.
  3. Insérez des données sur l'offre d'emploi dans une base de données.
  4. Envoyez un e-mail via un fournisseur tiers.
  5. Traiter un paiement avec un fournisseur tiers.

La procédure de retour en arrière serait

  • supprimer l'image du stockage de fichiers,
  • supprimer l'offre d'emploi de la base de données,
  • si l'e-mail a été envoyé, mais que le paiement a échoué : planifiez la demande de paiement pour une nouvelle tentative ultérieure.
JacquesB Aug 18 2020 at 21:56

"Meilleur" dépend évidemment des exigences. Le numéro 1 est clairement le plus simple à mettre en œuvre mais les transactions seront perdues/incomplètes en cas d'erreurs. Peut-être est-ce un compromis acceptable d'un point de vue commercial ?

La solution la plus robuste consiste à diviser le processus en une série d'étapes où chaque étape est une transaction. Une transaction est terminée ou a échoué, et si elle échoue, elle peut être réessayée en toute sécurité. (Par exemple, l'envoi d'un e-mail ou d'un sms serait une transaction.) Une ligne de base de données garde une trace des étapes qui ont été complétées.

Je ne pense pas que vous devriez demander au client d'appeler à chaque étape. Cela créerait un couplage étroit et augmenterait simplement la complexité. Demandez simplement au client d'appeler une seule demande avec toutes les données nécessaires, ce qui lance le flux de travail. Le client peut ensuite envoyer une demande périodique distincte pour interroger l'état si vous souhaitez afficher la progression.

La prise en charge de l'annulation est plus compliquée et (comme vous l'observez) pas toujours possible. Si une étape peut échouer d'une manière où l'ensemble du processus doit être rejeté (comme si une carte de crédit ne pouvait pas être valide), je pense qu'elle devrait être effectuée dans une étape de validation avant le démarrage du processus en plusieurs étapes. Cela vous permettra de donner une rétroaction synchrone au client et de demander au client d'examiner et de ressaisir les données.

AdrianL Aug 27 2020 at 01:00

Comme d'autres l'ont mentionné, idéalement, vous souhaitez regrouper toutes les pièces nécessaires pour une offre d'emploi réussie et avoir un client pour l'envoyer à votre backend en une seule demande. En tant que développeur mobile moi-même, je plaide toujours pour que les clients effectuent le moins de travail possible afin de préserver l'utilisation des données et la durée de vie de la batterie.

En ce qui concerne le backend, je suggérerais d'essayer d'abord d'insérer les informations les plus importantes dans db, puis d'essayer par exemple d'insérer des données supplémentaires après, comme une image de logo