2016-06-07 2 views
0

J'ai une structure de message RabbitMQ, où un message A est censé générer un certain nombre de messages, appelons-les B et C. Un message A est reçu par un processus de travail, qui le traite ensuite et génère des messages B et C.RabbitMQ message subséquent atomicité

Le processus de workflow supposé est la suivante:

  1. Recevez un message A avec ack=False
  2. Démarrer une transaction
  3. Exécuter un code
  4. Générer un message B
  5. Générer un message C
  6. Envoyer ack pour le message A
  7. complète la transaction

Dans tous les cas, un processus de travail meurt pendant le traitement des messages A, ou tout est n'a pas encore complété la transaction - Je voudrais RabbitMQ traiter le message A comme non remis et remis en file d'attente. RabbitMQ fonctionne en configuration hautement disponible si cela est pertinent.

Pourquoi question tente de dégager la documentation RabbitMQ here, indiquant:

En outre, RabbitMQ fournit aucune garantie atomicité même en cas d'opérations portant sur une seule file d'attente, par exemple une erreur pendant tx.commit peut entraîner l'apparition d'un sous-ensemble des publications de la transaction dans la file d'attente après un redémarrage du courtier.

  • Est-il possible que je pourrais obtenir le comportement que je voudrais dans le contexte de RabbitMQ ou tout autre logiciel faire la queue sur le marché?
  • Y at-il un moyen que je pourrais faire fonctionner cela pour plusieurs files d'attente avec RabbitMQ?

Répondre

0

Vous aurez besoin de beaucoup d'infrastructure (code) pour que cela fonctionne correctement. C'est plutôt difficile.

Vous pouvez envisager un bus de service. J'ai un libre. Net open source ici: http://shuttle.github.io/shuttle-esb/

Si vous n'êtes pas dans l'espace. NET ou ne sont pas intéressés par l'utilisation d'un bus de service, vous pouvez suivre une partie du code pour voir comment certaines de ces choses ont été assurée par Shuttle.Esb: https://github.com/Shuttle/Shuttle.Esb

Vous pouvez également jeter un oeil à la IdempotenceService ici: https://github.com/Shuttle/Shuttle.Esb.SqlServer/blob/master/Shuttle.ESB.SqlServer/Idempotence/IdempotenceService.cs

Lorsque vous utilisez le serveur idempotence (dans un gestionnaire) de tous les messages envoyés sont stockés dans un magasin de transaction (comme serveur sql dans ce cas) et sont seulement envoyés après que la gestion des messages s'est terminée avec succès.

Pour envoyer en dehors d'un gestionnaire de messages, on pourrait utiliser une boîte d'envoi transactionnelle (encore une fois, une file d'attente basée sur une table de serveur SQL fonctionnerait).

Le fait est que vous devez sérieusement réfléchir à votre conception et que cela va être difficile.

+0

Je sais exactement comment implémenter ceci - une solution SQL-soutenue serait une solution naïve à cela. Mon problème est de trouver le bon logiciel qui serait capable de le faire efficacement au niveau de performance RabbitMQ, plutôt que Postgres/MySQL. –

0

J'ai fait une erreur en ciblant le produit le plus populaire, comme il me semblait. ActiveMQ a un support complet pour la haute disponibilité et les transactions, donc je viens de passer à cela et mes problèmes sont partis.

0

Nous avons quelques systèmes qui fonctionnent exactement comme celui-ci dans la production, avec ce format de base:

  1. Get message A
  2. faire un travail
  3. Un message d'acquittement

Si l'étape 2 échoue, le message A est "remis en file d'attente" et disponible pour être repris.

Lorsqu'un message est envoyé à une file d'attente et reçu avec succès, ce message est marqué ready. Quand il est ensuite envoyé à un consommateur, il est marqué unacked jusqu'à ce qu'il soit reconnu par le consommateur, auquel cas il est retiré de la file d'attente.

Dans votre exemple, jusqu'à ce que vous avez reconnu le message à l'étape 6, il est encore à l'état unacked, ce qui signifie si le processus de travail est décédé avant l'étape 6 le message glisserait à l'état ready dans RabbitMQ, prêt à être envoyé à un autre travailleur.

Cette fonctionnalité repose sur le fait que vous ne désactivez pas explicitement les accusés de réception. Si vous l'étiez, je suis à peu près certain que les messages sont immédiatement retirés de la file d'attente lorsqu'ils sont envoyés à un consommateur.

+0

Que faire si vous devez envoyer un message B suivant le message A? De toute évidence, d'une manière atomique - "Ack et publier le message B" ou "Noack et le message B n'a jamais été publié"? –

+0

Dans ce cas, vous enverriez le message B pendant l'étape "_Do work_", donc si le message A est réceptionné, vous savez que le message B a été envoyé et vice versa. –

+0

Et si le message pouvait être envoyé, mais que le travail ne pouvait pas être fait? –