Compartir a través de


Control de transacciones

Receptores con transacciones

La principal diferencia entre los receptores de transacciones y los receptores no transactados es que los receptores de transacciones crean y usan una transacción MSDTC explícita para garantizar la atomicidad entre su origen de datos y la base de datos BizTalk Server MessageBox. En general, todos los demás aspectos del adaptador son iguales.

Cabe destacar que un adaptador de recepción de solicitud-respuesta solo usa una transacción para enviar el mensaje de solicitud original al motor de mensajería. Se necesita otra transacción para transmitir la respuesta enviada desde el motor de mensajería al adaptador. Esto se debe a que el ámbito de la primera transacción está comprendido entre el adaptador y la base de datos de cuadro de mensajes. El mensaje de solicitud posterior no se envía al adaptador desde el motor de mensajería hasta que se confirma la transacción correspondiente al mensaje de solicitud original.

En el diagrama de interacción de objetos que se muestra a continuación, se ilustra la interacción entre el adaptador y el motor de mensajería durante un envío transaccional de mensajes entrantes. En este ejemplo, tiene lugar la siguiente secuencia de interacciones:

  1. El adaptador obtiene un nuevo lote del motor.

  2. El adaptador crea una nueva transacción MSDTC.

  3. El adaptador realiza una lectura destructiva desde su origen de datos que se ha dado de alta en la transacción.

  4. El adaptador envía el mensaje.

  5. El adaptador llama a Done en el lote, pasando su transacción MSDTC y su puntero de devolución de llamada BatchComplete . El motor devuelve una interfaz IBTDTCCommitConfirm .

  6. El motor procesa el lote, llama al adaptador de nuevo en su implementación de BatchComplete y transmite el estado de su procesamiento de mensajes al adaptador.

  7. Si el lote se realizó correctamente, el adaptador confirma la transacción y llama a la API IBTDTCCommitConfirm.DTCCommitConfirm con una true confirmación de signo de valor.

    Imagen que muestra la interacción entre el adaptador y el motor de mensajería durante un envío transaccional de mensajes entrantes.

Transmisores con transacciones

Los adaptadores con transacciones son, en su mayoría, muy parecidos a los adaptadores sin transacciones. La diferencia principal reside en que el adaptador con transacción envía los datos del mensaje a un recurso que ha dado de alta en una transacción MSDTC.

Sugerencia de implementación: En el caso de los envíos de transacciones, el adaptador debe usar la misma transacción MSDTC para escribir los datos en el destino y eliminarlos a través de la llamada al método IBTTransportBatch.DeleteMessage . solo requieren transacciones estas dos operaciones. No es necesario realizar transacciones con cualquier otra operación, como IBTTransportBatch.Resubmit, IBTTransportBatch.MoveToNextTransport e IBTTransportBatch.MoveToSuspendQ . Esto se debe a que el motor usa de manera implícita una transacción, y estos tipos de operaciones no necesitan ser atómicas con respecto a su destino.

El diagrama siguiente de interacción de objetos ilustra las interacciones entre el adaptador y el motor. Todo ocurre en este orden:

  1. El motor obtiene un nuevo lote del adaptador.

  2. El motor agrega dos mensajes al nuevo lote.

  3. El motor llama a Done en el lote, lo que hace que el adaptador publique el lote en su cola de transmisión interna que recibe servicio su grupo de subprocesos.

  4. El adaptador crea una nueva transacción MSDTC.

  5. El adaptador transmite los mensajes dando de alta el destino en la transacción MSDTC. Por ejemplo, esto podría estar escribiendo en una base de datos de SQL Server.

  6. Después de la transmisión, el adaptador obtiene un nuevo lote del motor.

  7. El adaptador llama a DeleteMessage para los mensajes que ha transmitido correctamente.

  8. El adaptador llama a Done en el lote que pasa su transacción DTC. El motor devuelve una interfaz IBTDTCCommitConfirm .

  9. El motor procesa el lote y elimina los mensajes de la cola de la aplicación.

  10. El motor llama a la interfaz IBTBatchCallback del adaptador con información sobre el éxito de sus operaciones de eliminación.

  11. Si el lote se ha procesado correctamente, el adaptador confirma las transacciones.

  12. El adaptador llama a IBTDTCCommitConfirm.DTCCommitConfirm para informar al motor de que la transacción se ha confirmado correctamente.

    Imagen que muestra las interacciones entre el adaptador y el motor.

Adaptadores con transacciones de petición-respuesta

Al contrario que las recepciones bidireccionales, los envíos bidireccionales se pueden realizar mediante la misma transacción DTC. Los adaptadores de solicitud-respuesta transacted deben usar el mismo IBTTransportBatch para las operaciones SubmitResponseMessage y DeleteMessage . Este lote debe usar la misma transacción MSDTC usada para enviar y recibir el par de mensajes de petición-respuesta. De este modo se garantiza la atomicidad para el intercambio de mensajes de petición-respuesta.

Componentes de servicios y BYOT

Las API del motor de mensajería requieren que se proporcione una transacción MSDTC. No obstante, los componentes .NET están diseñados para usarse como componentes con servicios y no permiten la confirmación ni anulación de transacciones mediante programación. En lugar de ello, la transacción se confirma automáticamente en el tiempo de ejecución de COM+ en esa plataforma.

Para estos escenarios, el adaptador debe usar la aportación de una transacción propia (BYOT, Bring Your Own Transaction). Esto permite al adaptador crear una transacción MSDTC, crear una instancia del componente .NET que usa la transacción y permitir que dicho componente herede la transacción creada en lugar de crear la suya propia. .NET Framework proporciona System.EnterpriseServices.BYOT para este fin. El SDK BaseAdapter proporciona una clase auxiliar, BYOTTransaction, para este fin.

Evitar condiciones de anticipación

Al escribir un adaptador que crea un objeto de transacción y lo entrega a BizTalk Server, acepta la responsabilidad de escribir código que haga lo siguiente:

  • Resuelve los errores de los mensajes asociados al lote.

  • Decide el resultado final de la transacción asociada a la operación por lotes.

    El adaptador debe informar BizTalk Server sobre el resultado final de la transacción para mantener sus datos de seguimiento internos. El adaptador informa BizTalk Server del resultado llamando a DTCConfirmCommit. Si el adaptador no lo hace, se produce una pérdida de memoria considerable.

    Las dos tareas indicadas anteriormente (resolución de errores y decisión del resultado final) parecen bastante sencillas, pero en realidad se basan en información procedente de varios subprocesos:

  • El adaptador procesa errores en función de la información pasada por BizTalk Server a la devolución de llamada de BatchComplete en el adaptador. Esta devolución de llamada se produce en el subproceso del adaptador.

  • DTCConfirmCommit es un método en el objeto IBTDTCCommitConfirm . El lote IBTDTCCommitConfirm devuelve una instancia del objeto IBTTransportBatch::D one . Esta instancia está en el mismo subproceso que la llamada IBTTransportBatch::D one , que es diferente del subproceso del adaptador.

  • Por cada llamada que realiza el adaptador a IBTTransportBatch::D one hay una devolución de llamada correspondiente, BatchComplete, a la que llama el motor de mensajería en un subproceso independiente para notificar el resultado del envío por lotes. En BatchComplete , el adaptador debe confirmar o revertir la transacción en función de si el lote ha pasado o no. En cualquier caso, el adaptador debe llamar a DTCConfirmCommit para notificar el estado de la transacción al motor de mensajería.

    Existe una posible condición de carrera porque la implementación del adaptador de BatchComplete puede suponer que el objeto IBTDTCCommitConfirm devuelto por IBTTransportBatch::D one siempre está disponible cuando se ejecuta BatchComplete . Sin embargo, se puede llamar a BatchComplete en un subproceso independiente del motor de mensajería, incluso antes de que IBTTransportBatch::D one devuelva. Es posible que cuando el adaptador intente acceder al objeto IBTDTCCommitConfirm como parte de la implementación de BatchComplete , hay una infracción de acceso.

    En el siguiente ejemplo, se soluciona el problema mediante un evento. En este caso, se tiene acceso al puntero de la interfaz mediante una propiedad que utiliza el evento. El método get siempre espera a que set finalice.

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

Ahora asigne el valor devuelto de IBTTransportBatch::D one a esta propiedad y úselo en la llamada a BatchComplete .

Consulte también

Lotes de mensajes transaccionales