Cómo finalizar un adaptador
Los temas siguientes sirven de guía para el correcto apagado de un adaptador.
Finalizar un adaptador
Cuando el motor de mensajería se apaga, llama a IBTTransportControl. Finalice en cada adaptador en proceso. Una vez que vuelva este método, BizTalk Server destruirá el adaptador. Esto ocurre inmediatamente con los adaptadores nativos, pero en el caso de los adaptadores administrados puede llevar más tiempo debido al proceso de recolección de elementos no utilizados de .NET. El adaptador debe bloquear en Terminate y realizar cualquier trabajo de limpieza necesario hasta que esté listo para destruirse.
Finalizar adaptadores de recepción aislados
Los adaptadores de recepción aislados no tienen la llamada a Terminate en ellos porque no están hospedados en el servicio de BizTalk. En su lugar, deben llamar a IBTTransportProxy. TerminateIsolatedReceiver para notificar al motor de mensajería que está a punto de apagarse.
Limpiar objetos COM mediante Marshal.ReleaseComObject
Cuando se escribe código administrado que usa objetos COM, Common Language Runtime (CLR), genera objetos proxy que conservan las referencias a dichos objetos COM. Los objetos proxy son objetos administrados y están sujetos a las reglas habituales de recolección de elementos no utilizados. Existe el problema de que el recolector de elementos no utilizados solo ve la memoria asignada por los tiempos de ejecución de .NET y no es consciente del objeto COM. Los objetos proxy son pequeños, por lo que un objeto COM grande podría quedar en memoria si el recolector CLR de elementos no utilizados no tiene constancia de él.
Para evitar este problema, libere explícitamente objetos COM subyacentes cuando haya terminado con ellos, especialmente los objetos IBTTransportBatch . Para ello, llamas a Marshal. ReleaseComObject.
Nota
ReleaseComObject devuelve el número de referencias restantes y solo libera el objeto COM cuando este valor devuelto es cero. A menudo, se llama a ReleaseComObject en un bucle para asegurarse de que el objeto se libera. Una vez completado, debe llamar a SuppressFinalize en este objeto porque no hay nada que finalizar. El último paso consiste en comprobar si el objeto es realmente un objeto COM.
El código siguiente muestra el proceso que se acaba de describir:
if (Marshal.IsComObject (batch))
(
While (0 <Marshal.ReleaseComObject(batch)
;
GC.SuppressFinalize (batch);
Liberar explícitamente el objeto IBTTransportBatch devuelto desde GetBatch puede mejorar considerablemente el rendimiento.
Usar siempre Terminate al cerrar un adaptador
Para BizTalk Server reconocer el código como adaptador, debe implementar una interfaz denominada IBTTransportControl. Esa interfaz regula el modo en que BizTalk Server se comunica con su adaptador, y se define de este modo:
public interface IBTTransportControl
{
void Initialize(IBTTransportProxy transportProxy);
void Terminate();
}
La interfaz contiene dos métodos, Initialize y Terminate.
Inicialización
BizTalk Server llama al método Initialize después de cargar el ensamblado del adaptador. Hace esto con el fin de pasar el proxy de transporte (el principal componente de BizTalk Server) al adaptador. La implementación de Initialize simplemente almacena el proxy de transporte en una variable miembro.
Terminate
BizTalk Server llama al método Terminate en el apagado del servicio para dar tiempo al adaptador para finalizar la ejecución de todos los lotes. Esto hace que la implementación del método Terminate sea mucho más implicada.
El adaptador no debe volver desde una llamada Terminate hasta que se haya completado cualquier trabajo pendiente que tenga. Cuando BizTalk Server llama a Terminate, el adaptador debe intentar detener todas sus tareas actuales y no iniciar ninguna nueva.
Dado que Se llama a Terminate como parte del apagado del servicio, el administrador de control de servicios finaliza el proceso si el adaptador se bloquea perpetuamente en Terminate. En ese caso, verá la advertencia del Administrador de control de servicios cuando éste detenga el servicio de BizTalk Server. Si es posible, no finalice el adaptador de este modo prematuro. Si el adaptador no realiza correctamente el proceso de finalización y aún tiene subprocesos en ejecución cuando el proceso comienza a finalizar, puede que a veces vea un mensaje de infracción de acceso de BizTalk Server al apagar.
Dada la naturaleza asíncrona de la interfaz con BizTalk Server, es probable que bajo la carga aún haya muchos lotes y por tanto subprocesos en ejecución. La llamada a Terminate debe implementarse para esperar a la conclusión de cada lote que el adaptador ha ejecutado correctamente en BizTalk Server antes de continuar. La conclusión del lote se señala mediante la devolución de llamada de BatchComplete de BizTalk Server. La llamada a Terminate debe esperar a que se produzca cada batchComplete pendiente. No obstante, el lote debe ejecutarse correctamente. Es decir, la llamada a IBTTransportBatch::Done no debe producir un error. Si se produce un error en la llamada a IBTTransportBatch::Done , no hay ninguna devolución de llamada por lotes.
Una vez comprendido que debe agregar código de sincronización a su adaptador, la implementación es bastante sencilla.
Un enfoque sencillo consiste en implementar un objeto de sincronización compuesto con métodos enter y leave para los subprocesos de trabajo y un método de finalización que se bloquea mientras un subproceso sigue dentro de la ejecución protegida. (Por cierto, la solución es muy similar a la conocida estructura de varios lectores y de escritor único en la que los subprocesos de trabajo se pueden considerar lectores y el método terminate como escritor).
El método terminate es el siguiente:
void terminate ()
{
this.control.Terminate();
}
Para cada subproceso de trabajo:
If (!this.control.Enter())
return; // we can’t enter because Terminate has been called
try
{
// create and fill batch
batch.Done();
}
catch (Exception)
{
// we are not expecting a callback
This.control.Leave();
}
En la devolución de llamada de BizTalk Server:
batchComplete (…)
{
// the callback from BizTalk Server
// process results
this.control.Leave();
}
BizTalk Server incluye código de ejemplo ControlledTermination.cs en el ejemplo adaptador base, que muestra el mecanismo de sincronización que se describe aquí.