Les messages Zombies sont des messages qui ont été routés vers une orchestration en cours d’exécution à partir de la messageBox et ont été « en vol » lorsque l’instance de l’orchestration prend fin. Autrement dit, nous n’avons pas consommé tous les messages entrants dans cette instance d’orchestration.
Les causes les plus courantes sont les suivantes :
Pour plus d’informations, dirigez-vous vers https://docs.microsoft.com/fr-fr/biztalk/core/zombies-in-biztalk-server.
Quand des messages Zombies sont créés, nous avons des erreurs suivantes dans la console BizTalk :
Dans ce cas-là, nous devons réaliser une gestion des messages Zombies. Dans cet article, nous allons nous appuyer sur un exemple de Parallel Listen Receive pour détailler le problème et la cause, nous allons également proposer deux solutions pour résoudre ce problème.
Supposons que les messages que nous allons envoyer dans une orchestration sont des factures et modélisés comme suit :
Nous promouvons le champ « Year » et voici le schéma de propriété :
L’objectif étant de pouvoir faire une correlation sur ce champ « Year » dans l’orchestration.
Voici la vue globale de notre orchestration :
Pour la première shape de réception « ReceiveInvoice », nous allons initialiser une Correlation Set, nommée CorProperty et le Correlation Type de celui-ci est la propriété promue : Year (cf ci-dessous).
Créons une variable targetTime qui est de type System.DateTime pour la shape Expression WaitDelay, celle-ci va nous servir de compteur de temps :
targetTime = System.DateTime.Now.AddSeconds(120);
Dans notre exemple, nous ferons uniquement des traitements simples. Dans la shape AssignMessage :
msgInvoice = msgInvoiceIn; msgInvoice(*) = msgInvoiceIn(*); RefInvoice = xpath(msgInvoice, "string(/*[local-name()='Invoice']/*[local-name()='Reference'])"); Year = xpath(msgInvoice, "string(/*[local-name()='Invoice']/*[local-name()='Year'])"); RefInvoice = "Invoice_" + Year + "_" + RefInvoice; xpath(msgInvoice, "/*[local-name()='Invoice']/*[local-name()='Reference']") = RefInvoice;
Envoyons le message traité par le SendPort.
Créons une variable Boolean nommé vExisteNextInvoice, que nous initialisons à True pour condition de sortir de notre Boucle. Dans la boucle GestionNextInvoice et la branche gauche de la shape Listen, nous allons recevoir les prochaines factures, les faire traiter de la même façon et les envoyer au SendPort. En parralèle dans la branche droite, faisons un compteur de temps dans la shape :
targetTime.Subtract(System.DateTime.Now)
Quand nous arrivons à la fin du compteur, mettre vExisteNextInvoice à false pour sortir de la boucle.
Ajoutons ici de manière volontaire ue shape Délai (OthersProcess) pour créer des Zombies messages. En réel, ceci simule des traitements ou d’autres processus qu’on pourrait avoir à la suite.
Supposons que la première facture arrive dans la Receive, celle-ci déclenche l’orchestration et initialise une corrélation. L’orchestration sera en état Dehydrated, cette dernière attendant de recevoir de nouvelles factures ou que le délai soit terminé. C’est-à-dire que pendant le délai défini, les cas suivants peuvent survenir :
A la fin du délai, la branche droite sera exécutée, la variable vExisteNextInvoice sera mise à false et on sortira du loop de la réception et du traitement. Maintenant, si un nouveau message arrive, ce message devient un zombie message, il ne sera pas traité, donc l’orchestration sera suspendue. Nous avons la fameuse erreur « The instance completed without consuming all of its messages ».
Quand l’orchestration s’exécute à la fin du délai et vient de sortir de la boucle, à ce moment si des messages avec les mêmes correlation set sont arrivés, cela crée des Zombies messages.
Nous vous proposons deux solutions possibles pour cette problématique :
Voici l’idée : nous allons créer une autre boucle qui enveloppe la boucle de GestionNextInvoice, qui s’appellerait ZombiesHandle. La condition pour sortir de cette boucle étant la même, vExisteNextInvoice = false. Quand nous sortons de la boucle GestionNextInvoice,
vExisteNextInvoice = false.
Continuons d’autres traitements (OtherProcess), à la fin, ajoutons un nouveau listen shape, ce dernier ayant un délai très court, une seconde par exemple :
new System.TimeSpan(0,0,1)
Dans la branche gauche, nous allons copier le début de l’orchestration, c’est-à-dire que nous recevons une facture, initialisons le délai et faison les traitements pour les factures, et les envoyons pour terminer. A la fin de la branche gauche de ce Listen, nous réactivons la boucle ZombiesHandle : dans la shape StartNewListen, mettons :
vExisteNextInvoice = true;
De cette façon, la boucle GestionNextInvoice est réactivée et nous pouvons faire une nouvelle suite de processus.
Nous avons fait un délai très court pour capturer s’il y a de nouveaux messages arrivants. Si oui, la boucle est réactivée et les processus se suivent. Si non, l’instance de l’orchestration (pour le même correlation set) sera terminée très vite, même si des messages sont arrivés entre temps, une nouvelle instance de l’orchestration sera déclenchée. Donc le phénomène de messages zombies a été évité.
Après avoir déployé le projet dans BizTalk et bindé les ports, envoyons quelques messages factures de tests comme par exemple :
Dans le dossier émission, nous avons obtenu des messages factures traités comme suivant :
Lors de nos nombreux tests, nous n’avons pas rencontré de messages Zombies.
Dans cet article, nous avons donc mieux compris le fonctionnement des messages Zombies et proposé une solution afin de les minimiser.