11
votes

Comment s'assurer de l'idempoteur de message avec plusieurs consommateurs concurrents?

J'ai plusieurs consommateurs concurrents distribués à chacun des messages de tirage de la même file d'attente (transactionnelle). Je souhaite mettre en œuvre chaque consommateur en tant que récepteur Idempotent afin que je ne traite jamais le même message plus d'une fois ( à travers tous les consommateurs) même si un double arrive. Comment puis-je accomplir cela avec plusieurs consommateurs?

Ma première pensée est d'en quelque sorte générer un numéro de séquence consécutif pour chaque message avant de les mettre sur la file d'attente, puis utilisez une table de base de données partagée pour coordonner les travaux entre les consommateurs. C'est à dire. Le consommateur n ° 1 traite MSG n ° 1 puis écrit une ligne à la table de DB indiquant que «Msg n ° 1 est traité» (veulent que cela dans une base de données assure la durabilité). Lorsqu'un consommateur est prêt à traiter un message, il ressemble à la suivante disponible dans la file d'attente, consulte la table DB partagée et détermine s'il s'agit de la prochaine MSG dans l'ordre. Si tel est le cas, il tire la file d'attente. Sinon, il l'ignore.

De cette façon, je n'ai besoin que de stocker le dernier message traité (car il existe un numéro de séquence consécutif pour tous les MSG), je n'ai pas besoin d'utiliser un identifiant de stockage tampon de tous les messages reçus avec une "fenêtre" négociée. La taille et les messages sont toujours traités en série (ce que je veux pour ce scénario).

juste curieux s'il y a une meilleure façon? Je suis préoccupé par le coût d'interrogation de la base de données chaque fois que je dois traiter un message.

Si la réponse est "Cela dépend du cadre", j'ai eu MSMQ à l'esprit


0 commentaires

3 Réponses :


2
votes

Le point de récepteur idempotent est que cela n'a pas d'importance si un message est traité plusieurs fois. Par conséquent, les destinataires idempotents n'ont pas besoin de détecter d'une manière ou d'une autre pour détecter qu'un message est un duplicata, ils peuvent simplement le traiter comme d'habitude ...

Donc, votre récepteur n'est pas idempotent, ou vous êtes inquiétant inutilement ...


5 commentaires

Si la logique de traitement de mon API / Message est conçue de manière à être idempotente, je n'ai pas à vous soucier de recevoir des msgs en double. Ce n'est pas le cas pour mon scénario. Je dois filtrer les messages en double et non seulement pour une instance d'un consommateur, mais sur plusieurs instances.


Mais si je le seul moyen, je dois garantir une idempotence consiste à éviter les effets secondaires pour arriver une seconde fois?


Être idempotent est un détail de mise en œuvre, ce n'est pas la magie. Vous pouvez le faire soit en vous assurant que vos «messages» sont idempotents, tels que la valeur définie X à 5 ou en enregistrant le fait qu'un message a été traité. La meilleure façon d'accomplir ce dernier est de disposer de chaque message contenant un fichier GUID ou un autre ID unique et enregistrez-le dans la même transaction que vous modifiez l'état dans votre magasin de persistance. Pour chaque message, vérifiez si le GUID a déjà été traité, sachant que c'était dans la même transaction que l'état change.


Cela n'a aucun sens. Cette réponse implique que chaque morceau de code qui exécute lorsqu'un message est reçu doit être idempotent. C'est surréaliste.


Cette réponse doit être décochée comme une correction correcte. Par exemple. Le message reçu est "SendWelcomeMingemail" - vous devez conserver l'une ou l'autre voie si ce message est déjà traité, ou signalez-le d'une autre manière.



-2
votes

Andrew -

Une autre option consiste à examiner la façon dont votre file d'attente gère les messages. Il y a des files d'attente qui suppriment des messages après avoir été ramassés par un consommateur. C'est un comportement typique d'une file d'attente et il ne devrait pas être difficile de trouver une file d'attente avec ce type de fonctionnalité. Cela devrait vous fournir une solution simple au lieu de la construction d'une manière pour chaque consommateur de s'assurer qu'ils ne reçoivent pas de message qui a déjà été traité par un autre consommateur.

meilleur, Henry


2 commentaires

Cela n'aborde toujours pas les modes de défaillance dans lesquels un message a été "supprimé", le message a été traité et l'état persistait à la base de données, mais simplement comme le processus acompte le message qu'il échoue, ce qui signifie que le message sera replacé sur la file d'attente. et retraité à nouveau.


En règle générale, un message n'est pas supprimé, il suffit devenu indisponible pour être pris en charge jusqu'à ce que le cadre de file d'attente ait été traité avec succès. Si la file d'attente ne reçoit jamais l'ACK, le délai de traitement sera touché, puis le message sera remis sur la file d'attente en supposant qu'il a été configuré de cette manière. Votre cas d'utilisation est une situation bien connue et bien résolue.



9
votes

J'ai accompli des messages idempotents en veillant à ce que chaque message ait un GUID ou un autre identifiant unique, puis l'enregistrement dans la même transaction que vous modifiez l'état dans votre magasin de persistance.

Pour chaque message, vous pouvez maintenant vérifier si l'identifiant unique existe dans votre magasin de persistance.

Si l'identifiant unique existe, vous savez qu'il a été traité précédemment et que les modifications de l'état ont été persistées dans la même transaction.

Si l'identifiant unique n'existe pas, vous savez qu'il n'a jamais été traité.

Si deux consommateurs traitent le même message, car votre table dans laquelle vous stockez votre identifiant unique traitée a une contrainte unique, lorsqu'il s'agit de l'heure des deux consommateurs de commettre leurs transactions, l'un d'entre eux doit échouer et annuler toutes ses modifications. l'autre va réussir.


0 commentaires