Simple Message Queue (SMQ, formerly MNS) utilise une sémantique de livraison « au moins une fois ». Un consommateur peut donc recevoir le même message plusieurs fois. Implémentez une consommation idempotente pour garantir que votre logique métier ne s'exécute qu'une seule fois, quel que soit le nombre de livraisons du message.
Qu'est-ce que l'idempotence de la consommation ?
Une opération est idempotente lorsque son exécution répétée produit le même résultat que son exécution unique. Dans un système de messagerie, des exceptions réseau ou des pannes système peuvent entraîner la livraison multiple d'un même message. L'idempotence de la consommation garantit que votre logique métier s'exécute une seule fois, même si le message arrive à plusieurs reprises, évitant ainsi les opérations en double, telles qu'un double débit sur le compte d'un client.
Exemple : Un consommateur reçoit un message de déduction de paiement pour une commande d'un montant total de 100 USD. En raison d'exceptions réseau ou de pannes système, SMQ relivre le message et le consommateur le reçoit à plusieurs reprises. Grâce à l'idempotence de la consommation, le paiement n'est débité qu'une seule fois et un seul enregistrement de débit est écrit, indépendamment du nombre de réceptions du message.
Causes des livraisons en double
SMQ repose sur une sémantique de livraison « au moins une fois ». Dans les systèmes distribués, les situations suivantes peuvent provoquer la livraison multiple d'un même message :
Durée de traitement supérieure à la durée d'invisibilité : Si le consommateur A met plus de temps à traiter un message que la valeur définie par
InvisibleDuration, SMQ considère que le message n'a pas été traité et le livre au consommateur B. Les deux consommateurs traitent alors le même message.Panne réseau après un traitement réussi : Après avoir terminé le traitement d'un message, une panne réseau empêche l'appel
DeleteMessaged'atteindre SMQ. Lorsque le réseau est rétabli, SMQ relivre le message car il n'a jamais été supprimé.Redémarrage du broker ou du consommateur : Si un broker ou un consommateur redémarre après le traitement d'un message, mais avant que l'appel
DeleteMessagene soit finalisé, SMQ peut relivrer le message à l'expiration de la durée d'invisibilité.
Mise en œuvre de l'idempotence de la consommation
Choisir une clé d'idempotence
N'utilisez pas l'ID du message comme clé d'idempotence. Des messages ayant des ID différents peuvent contenir le même contenu. De plus, lorsqu'un client retransmet un message, la retransmission peut recevoir un nouvel ID. S'appuyer sur les ID de message empêcherait votre logique de déduplication de détecter les livraisons en double qu'elle est censée intercepter.
Déduisez plutôt votre clé d'idempotence d'un attribut métier stable qui identifie l'opération de manière unique. Par exemple :
Paiement de commande :
{orderId}/{operationType}, par exempleorder-9527/paymentMise à jour des stocks :
{itemSku}/{warehouseId}/{batchId}
La clé doit rester identique pour toutes les livraisons d'un même message logique et doit différer pour des opérations réellement distinctes.
Modèles de déduplication
Choisissez un ou plusieurs des modèles suivants en fonction de l'architecture de votre système :
Suivi par identifiant unique : Assignez un identifiant unique à chaque message. Lorsqu'un message est livré à un consommateur, enregistrez cet identifiant unique. Cela permet de s'assurer que le message ne sera pas consommé à nouveau par ce même consommateur.
Contrainte d'unicité en base de données : Ajoutez une contrainte d'unicité sur la colonne de la clé d'idempotence dans votre base de données. Lorsqu'un message en double arrive et que votre code tente d'insérer la même clé, la base de données rejette l'insertion avec une violation de contrainte. Interceptez cette erreur et traitez-la comme une opération sans effet réussie (no-op). Pour éviter une condition de concurrence entre la vérification et l'insertion, englobez ces deux actions dans une seule transaction ou utilisez une opération upsert.
Vérification de l'état métier : Avant d'exécuter toute logique, interrogez l'état actuel du message. Vérifiez si le message existe ou s'il a déjà été traité. Si c'est le cas, ignorez le traitement et retournez immédiatement. Ce modèle fonctionne bien lorsque vos opérations métier sont naturellement pilotées par l'état.
Fusion d'opérations : Pour les opérations commutatives ou accumulatives, concevez l'opération de sorte que son application multiple produise le même résultat que son application unique. Par exemple, utilisez
SET balance = Xau lieu deSET balance = balance - Y.