Traitement par lot des messages pour le traitement de réception
Rappels en lot
Les lots envoyés par les adaptateurs de réception au moteur de messagerie étant traités de façon asynchrone, l'adaptateur a besoin d'un mécanisme pour lier un rappel à un état quelconque au sein de l'adaptateur afin de pouvoir être notifié du succès ou de l'échec de l'opération et réaliser les actions de nettoyage nécessaires. La sémantique des rappels étant souple, les adaptateurs peuvent utiliser une des trois approches possibles ou les combiner. Ces règles sont les suivantes :
Tous les rappels sont effectués sur le même objet instance qui implémente IBTBatchCallBack.
Le cookie passé au moteur au moment où une requête de nouveau lot est effectuée est utilisé pour mettre le rappel en corrélation avec l'état au sein des adaptateurs.
Il existe un objet de rappel différent pour chaque lot qui implémente IBTBatchCallBack. Ici, chaque objet détient son propre état privé.
Une fois le lot traité, l’adaptateur est rappelé lors de son implémentation d’IBTBatchCallBack.BatchComplete. C'est le premier paramètre qui indique l'état global du lot, à savoir le paramètre HRESULT. Si la valeur de ce paramètre est supérieure ou égale à zéro, le lot a correctement été traité dans la mesure où le moteur devient propriétaire des données et où l'adaptateur est libre de supprimer ces données du câble. Un status négatif indique que le lot a échoué : aucune des opérations du lot n’a réussi et l’adaptateur est responsable de la gestion de la défaillance.
Si le lot a échoué, l'adaptateur a besoin de savoir quel élément de quelle opération a échoué. Par exemple, supposons que l’adaptateur lisait 20 fichiers à partir du disque et les envoyait dans BizTalk Server à l’aide d’un seul lot. Si le dixième fichier a été endommagé, l’adaptateur doit suspendre ce fichier et soumettre à nouveau les 19 autres. Ces informations sont disponibles pour l’adaptateur dans les deuxième et troisième paramètres (
opCount
nombre d’opérations) de type short etoperationStatus
, qui est de type BTBatchOperationStatus[].
Notes
Au sein d'un même objet de lot, un message ne doit jamais être envoyé plus d'une fois, au risque de provoquer des erreurs au niveau du moteur.
Le nombre d’opérations indique le nombre de types d’opérations dans le lot (la taille du tableau BTBatchOperationStatus ). Chaque élément du tableau d'état des opérations correspond à un type d'opération donné. À l’aide du tableau BTBatchOperationStatus , l’adaptateur peut déterminer quel élément d’une opération donnée a échoué en examinant le tableau BTBatchOperationStatus.MessageStatus pour les valeurs HRESULT négatives qui signifient un échec. Dans le scénario ci-dessus, l'adaptateur crée un nouveau lot qui contient 19 envois de message et un message suspendu.
Le fragment de code ci-dessous montre comment l'adaptateur demande un nouveau lot auprès du moteur par l'intermédiaire de son proxy de transport et envoie un seul message au moteur à l'aide de l'approche par cookie. Le moteur de messagerie appelle la méthode BatchComplete comme rappel de lot lorsqu’il a terminé le traitement de l’intégralité du lot de messages envoyés.
using Microsoft.BizTalk.TransportProxy.Interop;
using Microsoft.BizTalk.Message.Interop;
public class MyAdapter :
IBTTransport,
IBTTransportConfig,
IBTTransportControl,
IPersistPropertyBag,
IBaseComponent,
IBTBatchCallBack
{
private IBTTransportProxy _tp;
public void BatchComplete(
Int32 status,
Int16 opCount,
BTBatchOperationStatus[] operationStatus,
System.Object callbackCookie)
{
// Use cookie to correlate callback with work done,
// in this example the batch is to submit a single
// file the name of which will be in the
// callbackCookie
string fileName = (string)callbackCookie;
if ( status >= 0 )
// DeleteFile from disc
File.Delete(fileName);
else
// Rename file to fileName.bad
File.Move(fileName, fileName + ".bad");
}
private void SubmitMessage(
IBaseMessage msg,
string fileName)
{
// Note: Pass in the filename as the cookie
IBTTransportBatch batch =
_tp.GetBatch(this, (object)fileName);
// Add msg to batch for submitting
batch.SubmitMessage(msg);
// Process this batch
batch.Done(null);
}
}
Le Kit de développement logiciel (SDK) BizTalk Server inclut des exemples pour les adaptateurs suivants : Fichier, HTTP, MSMQ et l’adaptateur transactionnel. Tous ces adaptateurs reposent sur un bloc de construction commun appelé BaseAdapter. La version 1.0.1 de BaseAdapter inclut tout le code nécessaire à l'analyse de l'état des opérations et à la régénération des nouveaux lots à envoyer.
Condition d'engorgement
Les deux tâches que sont la résolution des erreurs et la décision concernant le résultat final d'un lot envoyé sont en apparence assez simples. En fait, elles s'appuient sur des informations provenant de plusieurs threads :
L’adaptateur traite les erreurs en fonction des informations transmises par BizTalk Server à la méthode de rappel BatchComplete de l’adaptateur. Ce rappel s'exécute sur le thread de l'adaptateur.
DTCCommitConfirm est une méthode sur l’objet IBTDTCCommitConfirm . Un instance de l’objet IBTDTCCommitConfirm est retourné par l’appel IBTTransportBatch ::D one par lot. Cette instance se trouve sur le même thread que l’appel IBTTransportBatch ::D one, qui est différent du thread de rappel de l’adaptateur.
Pour chaque appel que l’adaptateur effectue à IBTTransportBatch ::D one le moteur de messagerie effectue un appel correspondant à la méthode de rappel BatchComplete dans un thread distinct pour signaler le résultat de l’envoi du lot. Dans BatchComplete , l’adaptateur doit valider ou restaurer la transaction en fonction de la réussite ou de l’échec du lot. Dans les deux cas, l’adaptateur doit ensuite appeler DTCCommitConfirm pour signaler le status de la transaction.
Il existe une condition de race possible, car l’implémentation de BatchComplete par l’adaptateur peut supposer que l’objet IBTDTCCommitConfirm retourné par IBTTransportBatch ::D one est toujours disponible lors de l’exécution de BatchComplete . Toutefois, BatchComplete peut être appelé dans un thread de moteur de messagerie distinct, même avant que IBTTransportBatch ::D one retourne. Il est possible que lorsque l’adaptateur tente d’accéder à l’objet IBTDTCCommitConfirm dans le cadre de l’implémentation BatchComplete , il y ait une violation d’accès, car ce thread appelant n’existe plus. Utilisez la solution suivante pour éviter cette condition.
L'exemple suivant permet de résoudre le problème à l'aide d'un événement. Ici, le pointeur d'interface fait l'objet d'un accès par l'intermédiaire d'une propriété qui fait appel à un événement. La méthode get attend toujours que la méthode set soit terminée avant de poursuivre.
protected IBTDTCCommitConfirm CommitConfirm
{
set
{
this.commitConfirm = value;
this.commitConfirmEvent.Set();
}
get
{
this.commitConfirmEvent.WaitOne();
return this.commitConfirm;
}
}
protected IBTDTCCommitConfirm commitConfirm = null;
private ManualResetEvent commitConfirmEvent = new ManualResetEvent(false);
Codes d'état des lots
Le code d'état global du lot indique le résultat du lot. L'état de l'opération donne le code d'état de l'envoi pour chaque élément de message. Les lots peuvent échouer pour diverses raisons. Une erreur liée à la sécurité peut se produire ou le message peut avoir été envoyé au moment où le moteur était en cours d'arrêt. (En règle générale, lorsque le moteur s’arrête, il n’accepte aucun nouveau travail, mais permet de terminer le travail en cours.) Le tableau suivant indique certaines valeurs HRESULT courantes qui sont retournées dans le lot status ou dans l’opération status. Il indique également s'il s'agit d'un code de réussite ou d'échec. La gestion appropriée de ces codes est décrite plus en détail dans Comment gérer les défaillances d’adaptateur.
Code (défini dans la classe BTTransportProxy) | Code de réussite/d'échec | Description |
---|---|---|
BTS_S_EPM_SECURITY_CHECK_FAILED | Succès | Le port a été configuré pour effectuer une vérification de sécurité et supprimer les messages dont l'authentification a échoué. Les adaptateurs ne devraient pas suspendre les lots qui renvoient ce code d'état. |
BTS_S_EPM_MESSAGE_SUSPENDED | Succès | Indique qu'un ou que plusieurs messages ont été suspendus et que le moteur est propriétaire des données. Il s'agit d'un code de réussite dans la mesure où le moteur de messagerie a accepté les messages envoyés. |
E_BTS_URL_DISALLOWED | Échec | Un message a été envoyé avec un InboundTransportLocation non valide. |
Opérations de traitement par lots
Le tableau suivant détaille les méthodes membres et les opérations de l’objet IBTTransportBatch que l’adaptateur utilise pour ajouter du travail à un lot donné.
Nom de la méthode | Type d'opération | Description |
---|---|---|
SubmitMessage | Envoyer | Envoie un message au moteur. |
SubmitResponseMessage | Envoyer | Envoie un message de réponse au moteur. Il s'agit d'un message de réponse d'une paire sollicitation-réponse. |
DeleteMessage | Supprimer | Supprime un message qu'un adaptateur a correctement transmis sur le câble à l'aide d'un envoi non bloquant. Les adaptateurs qui utilisent des envois bloquants n’ont pas besoin d’appeler cette méthode, car le moteur de messagerie la supprime au nom de l’adaptateur si l’adaptateur retourne true à partir de TransmitMessage. |
MoveToSuspendQ | MoveToSuspendQ | Place un message dans la file d'attente de messages interrompus. |
Resoumettre | Resubmit | Demande qu'un message fasse l'objet d'un nouvel essai de transmission plus tard. Cette méthode est généralement appelée après qu'une tentative de transmission a échoué. |
MoveToNextTransport | MoveToNextTransport | Demande qu'un message soit transmis à l'aide de son transport secondaire. Cette méthode est généralement appelée lorsque le nombre maximal de tentatives est atteint. En l'absence de transport secondaire, cette méthode échoue. |
SubmitRequestMessage | SubmitRequest | Envoie un message de requête. Il s'agit d'un message de requête d'une paire requête-réponse. |
CancelRequestForResponse | CancelRequestForResponse | Notifie le moteur que l'adaptateur ne souhaite plus attendre le message de réponse d'une paire requête-réponse. |
Clear | N/D | Supprime toutes les tâches du lot. |
Done | N/D | Envoie un lot de messages à traiter au moteur. |
Gestion de Batch
Les lots sont implémentés en code natif au sein du moteur de messagerie. C'est pourquoi un adaptateur écrit en code géré devrait libérer le wrapper RCW (Runtime Callable Wrapper) pour le lot après avoir terminé le traitement du lot. Cette opération est effectuée dans le code managé à l’aide de l’API Marshal.ReleaseComObject . Il est important de souligner que cette API doit être appelée dans une boucle while tant que le nombre de références renvoyé atteigne zéro.
BizTalk Server traite les messages de manière synchrone au sein d’un lot. De nombreux lots pouvant être traités en même temps, ceci peut être une occasion pour optimiser l'adaptateur en ajustant la taille de lot dans le domaine d'application. Supposons, par exemple, que vous voulez traiter tous les fichiers d'un FTP (jusqu'à ce qu'une limite donnée soit atteinte) ou dans le cas de SAP, vous voulez traiter un seul flux dans un nombre de messages envoyés en tant que lot.
Le lot utilisé par un adaptateur pour renvoyer des opérations à BizTalk Server n’a pas besoin de correspondre exactement à la liste des messages que BizTalk Server donne à l’adaptateur. En d’autres termes, lorsque vous effectuez des envois transactionnels, vous devez fractionner les opérations de renvoi MoveToNextTransport et MoveToSuspendQ en lots distincts. De nombreux adaptateurs trient les lots de messages envoyés destinés à plusieurs points de terminaison dans des listes de messages distinctes qui feront l'objet de davantage de traitement.
Le fait est qu’il n’existe aucune règle (en dehors de celles associées à la transaction) associée au traitement par lot de messages dans BizTalk Server. Le traitement par lot est simplement un moyen spécifique à l’implémentation pour l’adaptateur de segmenter des messages dans et hors de BizTalk Server.
Un adaptateur peut traiter par lot des messages provenant de plusieurs lots plus petits que BizTalk Server lui a donnés dans un lot plus grand pour la réponse à BizTalk Server. Vous pouvez optimiser de manière sensible les adaptateurs transactionnels amenés à traiter de grands nombres de très petits messages. Cela réduit le rapport nombre de transactions par message.
En règle générale, BizTalk Server produit des lots côté envoi de 5 à 10 messages. S’il s’agit de très petits messages, un adaptateur peut traiter jusqu’à 100 messages ou plus avant de renvoyer un lot transactionnel de suppressions à BizTalk Server. Une telle optimisation n'est pas facile à implémenter. Vous devez vous assurer que les messages ne restent jamais coincés dans la mémoire de l'adaptateur en attendant indéfiniment qu'un seuil quelconque soit atteint.
L’importance du traitement par lot est visible dans les numéros de performances pour BizTalk Server pour les adaptateurs à haut débit comme MQSeries. Dans le cas de ces adaptateurs, les messages sont reçus au moins deux fois plus souvent qu'ils ne sont envoyés. Par défaut, l’adaptateur de réception utilise des lots de 100 messages et l’adaptateur d’envoi utilise la BizTalk Server lot par défaut qui lui est donné.
Lots transactionnels
Lorsque vous écrivez un adaptateur qui crée un objet transaction et le remet à BizTalk Server, vous acceptez la responsabilité d’écrire du code qui effectue les opérations suivantes :
Détermine le résultat final de l’opération de lot : valider ou mettre fin à la transaction. Cela peut dépendre d’autres branches transactionnelles dans l’étendue de cette transaction qui ne sont pas BizTalk Server dépendantes, telles que l’écriture dans une file d’attente Message Queuing (MSMQ) ou une opération de base de données transactionnelle.
Informe BizTalk Server du résultat final en appelant la méthode IBTDTCCommitConfirm.DTCCommitConfirm. Le retour
true
indique une validation réussie de la transaction ; le retourfalse
signifie l’échec et la restauration de la transaction.L’adaptateur doit informer BizTalk Server sur le résultat final de la transaction pour conserver ses données de suivi internes. L’adaptateur informe BizTalk Server du résultat en appelant DTCCommitConfirm. S'il ne le fait pas, une fuite de mémoire sensible se produit et la transaction MSDTC expire, puis échoue bien que ses opérations aient réussi.