Partager via


Remplacement des modèles pour les adaptateurs d'envoi

Les adaptateurs d'envoi sont des messages remis du moteur de messagerie BizTalk à transmettre sur le câble. Ces messages peuvent être envoyés via un modèle d'échange de message unidirectionnel ou bidirectionnel. Un adaptateur qui traite ce modèle d'échange de message bidirectionnel est nommé adaptateur de sollicitation-réponse.

Transmissions bloquantes et transmissions non bloquantes

Le moteur de messagerie remet des messages à l’adaptateur d’envoi à l’aide de la méthode IBTTransmitter.TransmitMessage ou de la méthode IBTTransmitterBatch.TransmitMessage , selon que l’adaptateur prend en compte les lots. Les deux versions de la méthode comportent une valeur de retour booléenne qui indique comment l'adaptateur a transmis le message. Si l’adaptateur retourne true, il a entièrement envoyé le message avant le retour. Dans ce cas, le moteur de messagerie supprime le message de la base de données MessageBox pour l'adaptateur. Si l’adaptateur retourne false, il a démarré la transmission des messages et renvoyé avant la fin de la transmission. Dans ce cas, l'adaptateur est responsable non seulement de la suppression du message de la file d'attente de son application mais aussi du traitement des erreurs de transmission qui nécessitent que le message soit extrait pour être transmis ou suspendu.

L’adaptateur retourné false est un appel non bloquant, ce qui signifie que le code d’implémentation TransmitMessage ne bloque pas le thread appelant du moteur de messagerie. L'adaptateur ajoute simplement le message à une file d'attente en mémoire prête à être transmise puis renvoie. L'adaptateur doit normalement disposer de sa propre réserve de threads qui traite la file d'attente en mémoire, transmet le message, puis informe le moteur du résultat de la transmission.

Les threads du moteur de messagerie sont généralement plus liés au processeur que ceux utilisés pour envoyer des données sur le réseau. L'utilisation combinée ces deux types de threads affecte les performances. Les envois non bloquants permettent de découpler ces deux types de threads et améliorent sensiblement les performances par rapport aux appels bloquants.

Le diagramme suivant présente la réserve de threads de l'adaptateur qui peuvent avoir tendance à être liés par les opérations d'E/S. La réserve de threads du moteur de messagerie BizTalk Server est davantage liée au traitement effectué par le processeur. En conservant deux réserves de threads différentes et en ne combinant pas le même type de thread, le système opère plus efficacement.

Diagramme montrant le pool de threads de l’adaptateur qui peut avoir tendance à être lié par des opérations d’E/S.

Conseil en matière de performances : Pour des performances optimales, les adaptateurs d’envoi doivent être non bloquants et prendre en charge les lots. Lorsque l'adaptateur BizTalk File est passé de bloquant et ne reconnaissant pas les lots à non bloquant et reconnaissant les lots, les performances ont été multipliées par trois.

Conseil de résolution des problèmes : Le blocage des transmissions peut entraîner une dégradation des performances d’un instance hôte entier. Si l’adaptateur effectue un blocage excessif dans TransmitMessage , cela empêchera les threads de moteur de remettre des messages à d’autres cartes.

Envois hors lots

Les adaptateurs qui ne prennent pas en charge les lots doivent implémenter IBTTransmitter comme décrit dans Interfaces pour un adaptateur d’envoi asynchrone. Pour chaque message dont l’adaptateur a besoin pour transmettre le moteur de messagerie appelle IBTTransmitter.TransmitMessage. Le diagramme d'interaction d'objets ci-dessous décrit la méthode standard de transmission des messages, qui comporte les étapes suivantes :

  1. Le moteur remet le message à l'adaptateur.

  2. L'adaptateur place le message dans une file d'attente en mémoire prête à être transmise.

  3. Un thread de la réserve de threads de l'adaptateur extrait le message de la file d'attente, lit la configuration du message, puis transmet le message sur le réseau.

  4. L'adaptateur reçoit un nouveau lot du moteur.

  5. L’adaptateur appelle DeleteMessage sur le lot, en transmettant le message qu’il vient de transmettre.

  6. L’adaptateur appelle Terminé sur le lot.

  7. Le moteur traite le lot et supprime le message de la file d'attente de l'application.

  8. Le moteur rappelle l’adaptateur pour l’informer du résultat de l’opération DeleteMessage .

    Image montrant l’adaptateur supprimant un seul message de la file d’attente de l’application.

    Le diagramme d'interaction d'objets précédent présente l'adaptateur supprimant un seul message de la file d'attente de l'application. L'idéal est que l'adaptateur regroupe les opérations de message plutôt que d'opérer sur un seul message à la fois.

Envois par lots

Les adaptateurs qui prennent en charge les lots doivent implémenter IBTBatchTransmitter et IBTTransmitterBatch , comme décrit dans Interfaces pour les adaptateurs d’envoi. Lorsque le moteur a des messages que l’adaptateur doit transmettre, le moteur obtient un nouveau lot de l’adaptateur en appelant IBTBatchTransmitter.GetBatch. L’adaptateur retourne un nouvel objet batch qui implémente IBTTransmitterBatch. Le moteur démarre ensuite le lot en appelant IBTTransmitterBatch.BeginBatch. Cette API dispose d'un paramètre Out qui permet à l'adaptateur de spécifier le nombre maximal de messages qu'il accepte dans le lot. Le cas échéant, l'adaptateur peut retourner une transaction DTC. Le moteur appelle ensuite IBTTransmitterBatch.TransmitMessage une fois pour que chaque message sortant soit ajouté au lot. Le nombre d'appels est supérieur à zéro mais inférieur ou égal à la taille maximale du lot indiquée par l'adaptateur. Lorsque tous les messages ont été ajoutés au lot, l’adaptateur appelle IBTTransmitterBatch.Done. À ce stade, l'adaptateur place généralement tous les messages du lot dans sa file d'attente en mémoire. L'adaptateur transmet les messages d'un ou plusieurs threads de sa propre réserve de threads comme dans le cas des adaptateurs ne reconnaissant pas les lots. Il informe ensuite le moteur du résultat de la transmission.

Le diagramme d'interaction d'objets suivant présente la transmission de deux messages par un adaptateur d'envois par lots.

Diagramme montrant la transmission de deux messages par un adaptateur d’envoi par lots.

Gestion des erreurs de transmission

La sémantique recommandée pour les erreurs de transmission est présentée dans la figure ci-dessous. Il ne s'agit que de recommandations non appliquées par le moteur de messagerie. Si besoin, vous pouvez développer un adaptateur ne suivant pas ces directives, mais dans ce cas procédez avec précaution. Par exemple, en règle générale, un adaptateur doit toujours déplacer les messages vers le transport secondaire une fois le nombre maximal de tentatives atteint.

Plus généralement, un transport peut avoir besoin d'utiliser plus de tentatives que le nombre de tentatives défini. Bien qu'il s'agisse d'un cas légèrement différent, ceci est acceptable car la couche de transport s'en trouve alors plus tolérante. En général, les API exposées par le moteur de messagerie sont conçues pour permettre à l'adaptateur un contrôle maximal lorsque cela est possible. Ce contrôle s'accompagne d'un niveau de responsabilité plus élevé.

Diagramme montrant le processus de gestion des échecs de transmission.

L’adaptateur détermine le nombre de nouvelles tentatives disponibles sur un message en vérifiant la propriété de contexte système RetryCount. L’adaptateur appelle l’API Resubmit une fois pour chaque nouvelle tentative et passe le message à soumettre à nouveau. Il transmet également l'horodatage indiquant quand le moteur doit remettre à nouveau le message à l'adaptateur. Cette valeur doit généralement être l’heure actuelle plus la valeur de RetryInterval. RetryInterval est une propriété de contexte système dont les unités sont en minutes. RetryCount et RetryInterval dans le contexte du message sont les valeurs configurées sur le port d’envoi. Considérez un déploiement évolutif avec les instances du même hôte BizTalk déployées sur plusieurs ordinateurs. Si le message est remis une fois l'intervalle de nouvelle tentative expiré, il peut être remis à n'importe laquelle des instances de l'hôte sur n'importe quel ordinateur où ces instances sont configurées pour s'exécuter. Pour cette raison, l'adaptateur ne doit conserver aucun état associé à un message à utiliser avec la nouvelle tentative car rien ne garantit que la même instance de l'adaptateur sera responsable de la transmission par la suite.

L'adaptateur doit uniquement tenter de déplacer le message vers le transport secondaire une fois le nombre de tentatives inférieur ou égal à zéro. Une tentative de déplacement du message vers le transport secondaire échoue si aucun transport secondaire n'est configuré pour le port. Dans ce cas, le message doit être suspendu.

Le fragment de code suivant indique comment déterminer le nombre de tentatives et l'intervalle à partir du contexte du message, ainsi que le nouvel envoi ou le déplacement suivant vers le transport secondaire.

using Microsoft.XLANGs.BaseTypes;  
using Microsoft.BizTalk.Message.Interop;  
using Microsoft.BizTalk.TransportProxy.Interop;  
 …  
// RetryCount and RetyInterval are system context properties...  
private static readonly PropertyBase RetryCountProperty =   
 new BTS.RetryCount();  
private static readonly PropertyBase RetryIntervalProperty =   
 new BTS.RetryInterval();  

public void HandleRetry(IBaseMessage msg, IBTTransportBatch batch)  
{  
int retryCount = 0;  
int retryInterval = 0;  

// Get the RetryCount and RetryInterval off the msg ctx...  
 GetMessageRetryState(msg, out retryCount, out retryInterval);  

// If we have retries available resubmit, else move to   
 // backup transport...  
 if ( retryCount > 0 )  
batch.Resubmit(  
 msg, DateTime.Now.AddMinutes(retryInterval));  
else  
batch.MoveToNextTransport(msg);  
}  

public void GetMessageRetryState(  
 IBaseMessage msg,   
 out int retryCount,   
 out int retryInterval )  
{  
retryCount = 0;  
retryInterval = 0;  

object obj =  msg.Context.Read(  
RetryCountProperty.Name.Name,    
RetryCountProperty.Name.Namespace);   

if ( null != obj )  
retryCount = (int)obj;  

obj =  msg.Context.Read(  
RetryIntervalProperty.Name.Name,    
RetryIntervalProperty.Name.Namespace);   

if ( null != obj )  
retryInterval = (int)obj;  
}  

Génération d'une exception à partir de TransmitMessage

Si l’adaptateur lève une exception sur l’une des API IBTTransmitter.TransmitMessage, IBTTransmitterBatch.TransmitMessage, IBTTransmitterBatch.Done, le moteur traite la transmission des messages impliqués comme des échecs de transmission et prend l’action appropriée pour le message, comme décrit dans Comment gérer les défaillances de l’adaptateur.

Pour les adaptateurs d'envoi reconnaissant les lots, la génération d'une exception sur l'API TransmitMessage a pour résultat d'effacer le lot entier et d'effectuer les opérations d'échec de transmission par défaut pour tous les messages de ce lot.

Sollicitation-réponse

Les adaptateurs d'envoi bidirectionnels prennent généralement en charge les transmissions unidirectionnelles et bidirectionnelles. L’adaptateur d’envoi détermine si le message doit être transmis sous forme d’envoi unidirectionnel ou bidirectionnel en inspectant la propriété de contexte système IsSolicitResponse dans le contexte du message.

Le fragment de code suivant illustre ceci :

private bool portIsTwoWay = false;  
private static readonly PropertyBase IsSolicitResponseProperty= new BTS.IsSolicitResponse();  

...  

 // Port is one way or two way...  
 object obj =  this.message.Context.Read(  
 IsSolicitResponseProperty.Name.Name,    
 IsSolicitResponseProperty.Name.Namespace);   

if ( null != obj )  
 this.portIsTwoWay = (bool)obj;  

Pendant une transmission de type sollicitation-réponse, l'adaptateur transmet le message de sollicitation. Une fois cette opération effectuée, il envoie la réponse associée et indique au moteur de messagerie de supprimer le message de sollicitation d'origine de la base de données MessageBox. La suppression du message de la file d'attente de l'application doit être effectuée dans le même lot de proxy de transport que l'envoi du message de réponse. Ceci assure l'atomicité de la suppression et de l'envoi de la réponse. Pour que l'atomicité soit totale, l'adaptateur doit utiliser une transaction DTC par laquelle la transmission du message de sollicitation vers une ressource reconnaissant les transactions, l'envoi du message de réponse et la suppression du message de sollicitation figurent toutes dans le contexte de la même transaction DTC. Comme toujours, nous recommandons que le message de sollicitation soit transmis via un envoi non bloquant.

Le fragment de code suivant illustre les aspects principaux d'un envoi bidirectionnel. Lorsque le moteur appelle IBTTransmitter.TransmitMessage , l’adaptateur met en file d’attente le message à transmettre à une file d’attente en mémoire. L’adaptateur retourne false pour indiquer qu’il effectue un envoi non bloquant. Le pool de threads de l’adaptateur (WorkerThreadThunk) traite la file d’attente en mémoire et supprime un message pour le transmettre à une méthode d’assistance. Cette méthode est responsable de l'envoi du message de sollicitation et de la réception du message de réponse. (L’implémentation de cette méthode d’assistance est en dehors de la portée de cette rubrique.) Le message de réponse est envoyé dans le moteur et le message de sollicitation est supprimé de la file d’attente de l’application.

using System.Collections;  
using Microsoft.XLANGs.BaseTypes;  
using Microsoft.BizTalk.Message.Interop;  
using Microsoft.BizTalk.TransportProxy.Interop;  

     static private Queue _transmitQueue = new Queue();  
  static private IBTTransportProxy _transportProxy = null;   
// IBTTransmitter...  
 public bool TransmitMessage(IBaseMessage msg)  
{  
// Add message to the transmit queue...  
lock(_transmitQueue.SyncRoot)  
 {  
_transmitQueue.Enqueue(msg);  
 }  

 return false;  
}  

 // Threadpool worker thread...   
private void WorkerThreadThunk()  
{  
try  
{  
 IBaseMessage solicitMsg = null;  

 lock(_transmitQueue.SyncRoot)  
 {  
 solicitMsg =   
 (IBaseMessage)_transmitQueue.Dequeue();  
}  

 IBaseMessage responseMsg = SendSolicitResponse(   
 solicitMsg );  
Callback cb = new Callback();  

IBTTransportBatch batch = _transportProxy.GetBatch(  
 cb, null);  
batch.SubmitResponseMessage( solicitMsg, responseMsg );  
batch.DeleteMessage( solicitMsg );  
batch.Done(null);  
}  
catch(Exception)  
{  
// Handle failure....  
}  
}  

static private IBaseMessage SendSolicitResponse(  
 IBaseMessage solicitMsg )  
{  
// Helper method to send solicit message and receive   
 // response message...  
IBaseMessage responseMsg = null;  
return responseMsg;  
}  

Envois dynamiques

Les ports d'envoi dynamique ne sont pas associés à une configuration d'adaptateur. Ils utilisent à la place la configuration du gestionnaire pour les propriétés par défaut nécessaires à l'adaptateur pour transmettre les messages sur un port dynamique. Par exemple, un adaptateur HTTP peut avoir besoin d'utiliser un proxy et de fournir des informations d'identification. Le nom d'utilisateur, le mot de passe et le port peuvent être spécifiés dans la configuration du gestionnaire, que l'adaptateur met en cache lors de l'exécution.

Pour que le moteur détermine le transport sur lequel un message dynamique doit être envoyé, OutboundTransportLocation est précédé de l’alias de l’adaptateur. Un adaptateur peut inscrire un ou plusieurs alias avec BizTalk Server au moment de l’installation. Le moteur analyse OutboundTransportLocation au moment de l’exécution pour trouver une correspondance. L’adaptateur est responsable de la gestion de OutboundTransportLocation avec ou sans l’alias qui lui est ajouté. La table suivante affiche quelques exemples d'alias inscrits pour des adaptateurs BizTalk prêts à l'emploi.

Alias d'adaptateur Adaptateur Exemple de OutboundTransportLocation
HTTP:// HTTP http://www. MyCompany.com/bar
HTTPS:// HTTP https://www. MyCompany.com/bar
mailto: SMTP mailto:A.User@MyCompany.com
FILE:// FILE FILE://C:\ MaSociété \%MessageID%.xml