Gestion des Messages Zombies dans BizTalk

Hao Wu
Publié par Hao
Catégorie : BizTalk
16/11/2020

Contexte

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 :

    • Terminate control messages : dans une orchestration, quand il existe un message de control qui annule le job en cours d’exécution, des messages zombies peuvent être créés en conséquence ;
    • Parallel listen receives : une instance d’orchestration est terminée au moment où de nouveaux messages entrent. Nous avons parlé de ce cas dans l’article (AGRÉGER DES MESSAGES DANS UNE ORCHESTRATION AVEC UN PIPELINE D’ENVOI).

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 :erreur 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.

 

Description d’un cas simple

Supposons que les messages que nous allons envoyer dans une orchestration sont des factures et modélisés comme suit :

schema Invoice

Nous promouvons le champ « Year » et voici le schéma de propriété :

Schema 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 :

orchestration zombie messages

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).

Correlation type

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.

 

Analyse

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 :

    1. aucun message n’a été envoyé par la suite ;
    2. de nouveaux messages qui ont les mêmes correlations set sont reçus : la branche gauche s’exécute ;
    3. de nouveaux messages qui ont les différentes correlations set sont reçus : des nouvelles orchestrations seront déclenchées.

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.

 

Solution

Nous vous proposons deux solutions possibles pour cette problématique :

    • Voici une proposition simple, nous pouvons augmenter le temps dans le délai de la boucle. Ceci permet d’avoir une fenêtre plus large pour recevoir des messages.
    • Une autre solution :

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.

orchestration solution

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é.

 

Test

Après avoir déployé le projet dans BizTalk et bindé les ports, envoyons quelques messages factures de tests comme par exemple :

message Invoice

Dans le dossier émission, nous avons obtenu des messages factures traités comme suivant :

message sorti

Lors de nos nombreux tests, nous n’avons pas rencontré de messages Zombies.

 

Conclusion

Dans cet article, nous avons donc mieux compris le fonctionnement des messages Zombies et proposé une solution afin de les minimiser.