Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Los adaptadores de envío reciben mensajes del motor de mensajería de BizTalk para transmitirse a través de la red. Estos mensajes se pueden enviar mediante un patrón de intercambio de mensajes unidireccional o bidireccional. Un adaptador que controla este patrón de intercambio de mensajes bidireccional se denomina adaptador de Solicit-Response.
Bloqueo frente a transmisiones sin bloqueo
El motor de mensajería entrega mensajes al adaptador de envío mediante el método IBTTransmitter.TransmitMessage o el método IBTTransmitterBatch.TransmitMessage , en función de si el adaptador es compatible con lotes. Ambas versiones del método tienen un valor devuelto booleano que indica cómo el adaptador ha transmitido el mensaje. Si el adaptador devuelve true, ha enviado completamente el mensaje antes de devolverlo. En este caso, el motor de mensajería elimina el mensaje de la base de datos de MessageBox en nombre del adaptador. Si el adaptador devuelve false, inició la transmisión de mensajes y devolvió antes de que se complete la transmisión. En este caso, el adaptador es responsable no solo de eliminar el mensaje de su cola de aplicaciones, sino también de controlar los errores de transmisión que requieren que el mensaje se vuelva a intentar para su transmisión o se suspenda.
El adaptador devuelve false, lo que constituye una llamada sin bloqueo, lo que significa que el código de implementación de TransmitMessage no bloquea el subproceso de llamada del motor de mensajería. El adaptador simplemente agrega el mensaje a una cola en memoria lista para transmitirse y, a continuación, devuelve. El adaptador debe tener su propio grupo de subprocesos que services la cola en memoria, transmite el mensaje y, a continuación, notifica al motor del resultado de la transmisión.
Los subprocesos del motor de mensajería suelen ser más enlazados a la CPU que los subprocesos usados para enviar datos a través de la conexión. La combinación de estos dos tipos de subprocesos tiene un impacto negativo en el rendimiento. Los envíos sin bloqueo permiten el desacoplamiento de estos dos tipos de subprocesos y producen una mejora significativa del rendimiento frente a las llamadas de bloqueo.
En el diagrama siguiente se muestra el grupo de subprocesos del adaptador, que puede tender a estar limitado por operaciones de E/S. El grupo de subprocesos del motor de mensajería de BizTalk Server está más limitado por el procesamiento de CPU. Al mantener dos grupos de subprocesos diferentes y no mezclar el mismo tipo de subprocesos, el sistema puede funcionar de forma más eficaz.
Sugerencia de rendimiento: Para obtener el mejor rendimiento, los adaptadores de envío deben ser no bloqueantes y conscientes del procesamiento por lotes. Cuando el adaptador de archivos de BizTalk se cambió de ser bloqueante y no compatible con lotes a ser no bloqueante y compatible con lotes, se logró un aumento del rendimiento al triple.
Sugerencia de solución de problemas: El bloqueo de las transmisións puede provocar una degradación del rendimiento de una instancia de host completa. Si el adaptador bloquea demasiado en TransmitMessage, impedirá que los subprocesos del motor entreguen mensajes a otros adaptadores.
Envíos no agrupados
Los adaptadores que no son compatibles con lotes deben implementar IBTTransmitter como se detalla en Interfaces para un adaptador de envío asincrónico. Para cada mensaje que el adaptador necesita para transmitir el motor de mensajería llama a IBTTransmitter.TransmitMessage. En el diagrama de interacción de objetos siguiente se detalla el enfoque típico para transmitir mensajes, que consta de los pasos siguientes:
El motor entrega el mensaje al adaptador.
El adaptador coloca el mensaje en una cola en memoria lista para ser transmitida.
Un subproceso del grupo de subprocesos del adaptador extrae el mensaje de la cola, lee la configuración del mensaje y transmite el mensaje por el cable.
El adaptador recibe un nuevo lote del motor.
El adaptador llama a DeleteMessage en el lote y pasa el mensaje que acaba de transmitir.
El adaptador llama a Done en el lote.
El motor procesa el lote y elimina el mensaje de la cola de aplicaciones.
El motor llama al adaptador para notificarle del resultado de la operación DeleteMessage.
En el diagrama de interacción del objeto anterior se muestra el adaptador que elimina un único mensaje de la cola de aplicaciones. Idealmente, el adaptador agrupa por lotes las operaciones de mensaje en lugar de funcionar en un solo mensaje a la vez.
Envíos por lotes
Los adaptadores que son compatibles con lotes deben implementar IBTBatchTransmitter e IBTTransmitterBatch como se detalla en Interfaces para adaptadores de envío. Cuando el motor tiene mensajes para que el adaptador los transmita, el motor obtiene un nuevo lote desde el adaptador llamando a IBTBatchTransmitter.GetBatch. El adaptador devuelve un nuevo objeto por lotes que implementa IBTTransmitterBatch. A continuación, el motor inicia el lote llamando a IBTTransmitterBatch.BeginBatch. Esta API tiene un parámetro out que permite al adaptador especificar el número máximo de mensajes que aceptará en el lote. El adaptador puede devolver opcionalmente una transacción DTC. A continuación, el motor llama a IBTTransmitterBatch.TransmitMessage una vez para cada mensaje saliente que se va a agregar al lote. El número de veces que se llama es mayor que cero, pero menor o igual que el tamaño máximo del lote, como se indica en el adaptador. Cuando se han agregado todos los mensajes al lote, el adaptador llama a IBTTransmitterBatch.Done. En este momento, el adaptador suele encolar todos los mensajes del lote en su cola en memoria. El adaptador transmite los mensajes desde un subproceso o varios subprocesos en su propio grupo de subprocesos, como en el caso de los adaptadores que no gestionan lotes. A continuación, el adaptador notifica al motor el resultado de la transmisión.
En el siguiente diagrama de interacción de objetos se muestra la transmisión de dos mensajes por un adaptador de envío por lotes.
Control de errores de transmisión
La semántica recomendada para los errores de transmisión se muestra en la ilustración siguiente. Estas son solo recomendaciones y no son aplicadas por el motor de mensajería. Puede desarrollar un adaptador que se desvíe de estas instrucciones si hay motivos válidos para hacerlo, pero debe tener cuidado en este caso. Por ejemplo, en general, un adaptador siempre debe mover mensajes al transporte de copia de seguridad una vez agotados todos los reintentos.
Normalmente, un transporte puede necesitar usar más reintentos de los que están configurados. Aunque esto es ligeramente diferente, se considera aceptable porque se está aumentando la resistencia de la capa de transporte. En general, las API expuestas por el motor de mensajería están diseñadas para proporcionar al adaptador el control máximo siempre que sea posible. Con este control viene un mayor nivel de responsabilidad.
El adaptador determina el número de reintentos disponibles en un mensaje comprobando la propiedad de contexto del sistema RetryCount. El adaptador llama a la API Resubmit una vez para cada intento de reintento y pasa el mensaje para que se vuelva a enviar. Junto con el mensaje, pasa la marca de tiempo que indica cuándo el motor debe devolver el mensaje al adaptador. Este valor normalmente debe ser la hora actual más el valor de RetryInterval. RetryInterval es una propiedad de contexto del sistema cuyas unidades son minutos. RetryCount y RetryInterval en el contexto del mensaje son los valores configurados en el puerto de envío. Considere una implementación escalada horizontalmente con instancias del mismo host de BizTalk implementado en varios equipos. Si el mensaje se entrega después de que haya expirado el intervalo de reintento, el mensaje puede entregarse a cualquiera de las instancias del host en cualquiera de los equipos en los que están configurados para ejecutarse. Por este motivo, el adaptador no debe contener ningún estado asociado a un mensaje que se usará en el reintento porque no hay ninguna garantía de que la misma instancia del adaptador será responsable de la transmisión en un momento posterior.
El adaptador solo debe intentar mover el mensaje al transporte de copia de seguridad después de que el recuento de reintentos sea menor o igual que cero. Si no hay ningún transporte de copia de seguridad configurado para el puerto, se producirá un error al intentar mover el mensaje al transporte de copia de seguridad. En este caso, el mensaje debe suspenderse.
En el siguiente fragmento de código se ilustra cómo determinar el recuento de reintentos y el intervalo a partir del contexto del mensaje, así como el posterior reenvío o traslado al transporte de respaldo.
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;
}
Lanzar una excepción desde TransmitMessage
Si el adaptador produce una excepción en cualquiera de las API IBTTransmitter.TransmitMessage, IBTTransmitterBatch.TransmitMessage, IBTTransmitterBatch.Done, el motor trata la transmisión de los mensajes implicados como errores de transmisión y toma la acción adecuada para el mensaje, como se detalla en How to Handle Adapter Failures.
En el caso de los adaptadores de envío compatibles con lotes, arrojar una excepción en la API de TransmitMessage resulta en que se borre todo el lote y se realicen las acciones predeterminadas de fallo de transmisión para todos los mensajes de ese lote.
Solicit-Response
Los adaptadores de envío bidireccionales suelen admitir transmisiones unidireccionales y bidireccionales. El adaptador de envío determina si el mensaje se debe transmitir como un envío unidireccional o bidireccional inspeccionando la propiedad de contexto del sistema IsSolicitResponse en el contexto del mensaje.
El fragmento de código siguiente muestra esto:
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;
Durante una transmisión de solicitud-respuesta, el adaptador transmite el mensaje de solicitud. Una vez completado, envía la respuesta asociada e indica al motor de mensajería que elimine el mensaje de solicitud original de la base de datos MessageBox. La acción de eliminar el mensaje de la cola de aplicaciones debe realizarse en el mismo lote de proxy de transporte que el envío del mensaje de respuesta. Esto garantiza la atomicidad de la eliminación y el envío de la respuesta. Para una atomicidad completa, el adaptador debe usar una transacción DTC en la que la transmisión del mensaje de solicitud a un recurso compatible con transacciones, el envío del mensaje de respuesta y la eliminación del mensaje de solicitud están todos en el contexto de la misma transacción DTC. Como siempre, se recomienda que el mensaje de solicitud se transmita mediante un envío sin bloqueo.
En el fragmento de código siguiente se muestran los aspectos principales de un envío bidireccional. Cuando el motor llama a IBTTransmitter.TransmitMessage, el adaptador encola el mensaje que se va a transmitir en una cola de memoria. El adaptador devuelve false para indicar que está realizando un envío sin bloqueo. El grupo de subprocesos del adaptador (WorkerThreadThunk) gestiona la cola en memoria y desencola un mensaje para entregarlo a un método auxiliar. Este método es responsable de enviar el mensaje de solicitud y recibir el mensaje de respuesta. (La implementación de este método auxiliar está fuera del ámbito de este tema). El mensaje de respuesta se envía al motor y el mensaje de solicitud se elimina de la cola de aplicaciones.
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;
}
Envíos dinámicos
Los puertos de envío dinámicos no tienen la configuración del adaptador asociada. En su lugar, usan la configuración del controlador para las propiedades predeterminadas que el adaptador necesita para transmitir mensajes en un puerto dinámico. Por ejemplo, un adaptador HTTP puede necesitar usar un proxy y tener que proporcionar credenciales. El nombre de usuario, la contraseña y el puerto se pueden especificar en la configuración del controlador que el adaptador almacena en caché en tiempo de ejecución.
Para que el motor determine el transporte por el que se enviará un mensaje dinámico, OutboundTransportLocation tiene como prefijo el alias del adaptador. Un adaptador puede registrar uno o varios alias con BizTalk Server en el momento de la instalación. El motor analiza OutboundTransportLocation en tiempo de ejecución para buscar una coincidencia. El adaptador es responsable de controlar OutboundTransportLocation con o sin el alias antepuesto. En la tabla siguiente se muestran algunos ejemplos de alias registrados para adaptadores de BizTalk predefinidos.
| Alias del adaptador | Adaptador | Ejemplo de OutboundTransportLocation |
|---|---|---|
| HTTP:// | HTTP | http://www. MyCompany.com/bar |
| HTTPS:// | HTTP | https://www. MyCompany.com/bar |
| mailto: | SMTP | mailto:A.User@MyCompany.com |
| ARCHIVO:// | ARCHIVO | FILE://C:\ MyCompany \%MessageID%.xml |