Idempotence : éviter de traiter deux fois la même demande
Un paiement sans réponse peut avoir réussi. L’idempotence permet de réessayer sans double débit, à condition de reconnaître la demande et garder son résultat.
Article
Un service ralentit ou un message revient en double : timeout, retry, outbox et idempotence répondent à des risques différents. Voici comment les combiner.
Un service devient lent. Tous ses clients réessaient immédiatement et lui envoient encore plus de demandes : le mécanisme de reprise aggrave la panne. Pour éviter cela, il faut limiter l'attente et les nouvelles tentatives, puis traiter les doublons possibles. Timeout, retry et outbox répondent chacun à une partie du problème ; leur choix dépend de l'opération à protéger.
Avant d'ajouter un mécanisme, nommez le risque : une attente trop longue, trop d'appels simultanés, une opération exécutée deux fois ou un message jamais publié. Le tableau associe chaque protection au problème qu'elle traite.
| Famille | Outil | Ce qu'il traite |
|---|---|---|
| Borner l'attente | timeout | le temps accordé à l'autre |
| circuit breaker | l'acharnement sur une dépendance en panne | |
| bulkhead | la saturation qui se propage | |
| Réessayer sans nuire | retry borné | l'erreur transitoire |
| backoff et jitter | les clients qui réessaient tous ensemble | |
| Fiabiliser le traitement des messages | idempotence | le doublon et le rejeu |
| outbox | l'événement perdu entre la base et le bus | |
| inbox | l'événement republié en double | |
| file de rebut | ce qui n'a pas pu être traité |
Aucun de ces mécanismes ne décide si une vente peut attendre ou si un affichage ancien reste acceptable. Cette décision métier détermine les réglages : durée d'attente, nombre d'essais et réaction après leur échec.
Un timeout fixe le temps pendant lequel le client attend une réponse. Son expiration ne prouve pas que le serveur a arrêté son travail. Un paiement peut avoir réussi alors que le client reçoit une erreur de délai ; le relancer demande une protection contre le double débit.
Un circuit breaker, ou coupe-circuit, suspend temporairement les appels après des échecs répétés. Il permet ensuite quelques appels de test avant de rétablir le trafic. Les états fermé, ouvert et semi-ouvert décrivent ces phases, détaillées par Martin Fowler.
Un bulkhead isole les ressources utilisées par des traitements différents. Vous pouvez, par exemple, réserver un nombre limité de tâches simultanées à la messagerie pour qu'un blocage du fournisseur ne consomme pas toutes les capacités de l'application. Le nom vient des cloisons étanches des navires.
Le retry traite les erreurs transitoires, à trois conditions :
Si tous les clients attendent exactement la même durée, ils risquent de recommencer ensemble. Le jitter ajoute une variation aléatoire pour étaler leurs appels. Les simulations publiées par Marc Brooker chez AWS en 2015 montrent l'intérêt de cette variation par rapport à un délai croissant sans hasard.
Surtout, ne réessayez que les erreurs rejouables. Réessayer une requête malformée ne la rendra pas valide, et ajoutera du bruit à la panne.
L'idempotence permet de répéter une demande sans multiplier son effet métier. Elle peut être naturelle, comme fixer une valeur, ou obtenue en reconnaissant une demande déjà traitée. Elle est particulièrement utile lorsqu'une nouvelle tentative suit une réponse perdue.
Une clé stable peut identifier la demande ; un enregistrement fiable permet de retrouver son résultat. Il faut également empêcher deux traitements simultanés d'exécuter la même demande. Cette protection traite les doublons, tandis qu'un numéro de version ou un transport ordonné traite les messages reçus dans le mauvais ordre.
Une outbox enregistre dans la même transaction le changement métier et le message à publier. Si la transaction réussit, les deux sont conservés. Un relais récupère ensuite les messages en attente pour les envoyer, comme le décrit le pattern Transactional outbox.
Cette organisation évite le cas où les données sont modifiées puis où le processus s'arrête avant d'enregistrer le message. Le relais doit encore être surveillé et reprendre les envois qui échouent.
Le relais peut envoyer deux fois le même événement si la confirmation du premier envoi est perdue. Le destinataire doit donc reconnaître les doublons. Une inbox conserve les identifiants des messages traités, avec des garanties d'enregistrement cohérentes avec l'effet métier. D'autres traitements peuvent être naturellement idempotents.
Un effet métier unique dépend ainsi du traitement complet, pas seulement du transport du message. Tyler Treat explique cette distinction à propos des garanties de livraison.
Une file de rebut, ou dead letter queue (DLQ), conserve les messages qui n'ont pas pu être traités. Elle permet aux autres de continuer lorsque c'est acceptable. Il faut une alerte, un responsable et une procédure de correction ou de reprise ; déplacer le message ne répare pas son échec.
Pour chaque dépendance, précisez ce que l'application fait si elle ne peut plus obtenir la réponse attendue. L'arbitrage de CAP aide à raisonner sur les pertes de communication ; d'autres retards peuvent aussi apparaître dans un monolithe, par exemple avec une tâche de fond.
Le besoin de protection dépend du mécanisme réel. Un appel local dans une transaction, une file asynchrone et une requête réseau ne présentent pas les mêmes pannes. Après avoir choisi les responsabilités des modules, vérifiez les conditions dans lesquelles leurs échanges peuvent échouer.
La méthode tient en quatre partis pris :
En pratique, ces partis pris donnent une grille de questions à poser avant de franchir une frontière :
Je n'ajouterais pas tous ces mécanismes par défaut. Un appel local simple peut suffire là où une file et ses reprises multiplieraient les états à surveiller. Choisissez chaque protection à partir d'une panne identifiée et vérifiez qu'elle produit bien le comportement prévu.
Explorer
Choisis dans l’index d’après les étiquettes de cet article — les plus proches d’abord, hors de sa série. Rien n’est écrit à la main : un article publié demain avec les mêmes étiquettes y prendra place.
Un paiement sans réponse peut avoir réussi. L’idempotence permet de réessayer sans double débit, à condition de reconnaître la demande et garder son résultat.
Une réponse perdue ne signifie pas que l’opération a échoué. Méthodes HTTP, clés d’idempotence et suivi du résultat aident à réessayer sans créer de doublon.
Une commande expédiée met à jour une liste et déclenche un courriel. Ces effets ne se réparent pas de la même façon : voici comment organiser leur reprise.
Laisser un commentaire
Votre commentaire sera relu avant d'être publié.