Control de mensajes dudosos

Un mensaje dudoso es un mensaje que ha superado el número máximo de intentos de entrega a la aplicación. Esta situación se puede presentar cuando una aplicación basada en cola no puede procesar un mensaje debido a los errores. Para satisfacer la confiabilidad que exige, una aplicación en cola recibe los mensajes bajo una transacción. Anular la transacción en la que un mensaje en cola se recibió deja el mensaje en la cola para que el mensaje se vuelva a intentar con una nueva transacción. Si no se corrige el problema que produjo la anulación de la transacción, la aplicación receptora se puede atascar en una recepción de bucle y anulando el mismo mensaje hasta que supere el número máximo de intentos de entrega, y se produzca un mensaje dudoso.

Un mensaje se puede volver un mensaje dudoso por muchas razones. Las razones más comunes son específicas de la aplicación. Por ejemplo, si una aplicación lee un mensaje de una cola y realiza algún procesamiento de base de datos, es posible que la aplicación no pueda obtener un bloqueo en la base de datos, haciendo que se anule la transacción. Dado que la transacción de base de datos se anula, el mensaje permanece en la cola, lo que hace que la aplicación vuelva a leer el mensaje una segunda vez y realice otro intento de adquirir un bloqueo en la base de datos. Los mensajes también se pueden volver dudosos si contienen la información no válida. Por ejemplo, un pedido de compra puede contener un número del cliente no válido. En estos casos, la aplicación puede anular voluntariamente la transacción y forzar al mensaje a convertirse en un mensaje dudoso.

En raras ocasiones, se puede producir un error en la distribución a la aplicación. La capa de Windows Communication Foundation (WCF) puede encontrar un problema con el mensaje, por ejemplo, si el mensaje tiene un marco incorrecto, credenciales de mensaje no válidas adjuntas o un encabezado de acción no válido. En estos casos, la aplicación nunca recibe el mensaje; sin embargo, el mensaje todavía se puede convertir en un mensaje dudoso y procesar manualmente.

Control de mensajes dudosos

En WCF, el control de mensajes dudosos proporciona un mecanismo para que una aplicación receptora se ocupe de los mensajes que no se pueden enviar a la aplicación o los mensajes que se envían a la aplicación pero que producen un error cuando se procesan debido a razones específicas de la aplicación. El control de mensajes dudosos se configura mediante las siguientes propiedades en cada uno de los enlaces en cola disponibles:

  • ReceiveRetryCount. Un valor entero que indica el número máximo de horas para reintentar la entrega de un mensaje de la cola de la aplicación a la aplicación. El valor predeterminado es 5. Esto es suficiente en casos donde un reintento inmediato corrige el problema, como ocurre con un interbloqueo temporal en una base de datos.

  • MaxRetryCycles. Un valor entero que indica el número máximo de ciclos de reintento. Un ciclo de reintento consiste en transferir un mensaje de la cola de la aplicación a una subcola de intento y, después de un retraso configurable, de la subcola de intento de vuelta a la cola de la aplicación para reintentar la entrega. El valor predeterminado es 2. En Windows Vista, el mensaje se intenta un máximo de (ReceiveRetryCount +1) * (MaxRetryCycles + 1) veces. MaxRetryCycles se omite en Windows Server 2003 y Windows XP.

  • RetryCycleDelay. El tiempo de retardo entre los ciclos de reintento. El valor predeterminado es de 30 minutos. MaxRetryCycles y RetryCycleDelay proporcionan juntos un mecanismo para resolver el problema donde un reintento después de un retraso periódico corrige el problema. Por ejemplo, esto controla un conjunto de filas bloqueado en confirmación de la transacción pendiente de SQL Server.

  • ReceiveErrorHandling. Una enumeración que indica la acción a realizar para un mensaje en el que se ha producido un error tras intentar el número máximo de reintentos. Los valores pueden ser Fault, Drop, Reject, y Move. La opción de unidad predeterminada es Fault.

  • Fault. Esta opción envía un error al agente de escucha que provocó el error en ServiceHost. El mensaje debe ser eliminado de la cola de la aplicación por algún mecanismo externo antes de que la aplicación pueda continuar procesando los mensajes de la cola.

  • Drop. Esta opción quita el mensaje dudoso y el mensaje nunca llega a la aplicación. Si la propiedad TimeToLive del mensaje ha expirado en este punto, el mensaje puede aparecer en la cola de mensajes no enviados del remitente. Si no, el mensaje no aparece en ningún sitio. Esta opción indica que el usuario no ha especificado qué hacer si se pierde el mensaje.

  • Reject. Esta opción solo está disponible en Windows Vista. Indica a Message Queue Server (MSMQ) que devuelva una confirmación negativa al administrador de la cola emisora para indicar que la aplicación no puede recibir el mensaje. El mensaje se coloca en la cola de mensajes no enviados del administrador de la cola emisora.

  • Move. Esta opción solo está disponible en Windows Vista. Mueve el mensaje dudoso a una cola de mensajes dudosos para ser procesado posteriormente por una aplicación de control de mensajes dudosos. La cola de mensajes dudosos es una subcola de la cola de la aplicación. Una aplicación de control de mensajes dudosos puede ser un servicio WCF que lee los mensajes fuera de la cola de dudosa. La cola dudosa es una subcola de la cola de la aplicación y se puede direccionar como .msmq://<machine-name>/applicationQueue;poison, donde machine-name es el nombre del equipo en el que reside la cola y applicationQueue es el nombre de la cola específica de la aplicación.

A continuación, se muestra el número máximo de intentos de entrega realizados para un mensaje:

  • ((ReceiveRetryCount+1) * (MaxRetryCycles + 1)) on Windows Vista.

  • (ReceiveRetryCount + 1) on Windows Server 2003 and Windows XP.

Nota

No se realiza ningún reintento para un mensaje que se entrega correctamente.

Para realizar un seguimiento del número de veces que se intenta leer un mensaje, Windows Vista mantiene una propiedad de mensaje duradera que cuenta el número de anulaciones, así como una propiedad de recuento de movimiento que cuenta el número de veces que el mensaje se mueve entre la cola de la aplicación y las subcolas. El canal WCF lo utiliza con frecuencia para calcular los reintentos de recepción y el recuento de ciclos de reintento. En Windows Server 2003 y Windows XP, el canal WCF mantiene el recuento de anulaciones en la memoria y se restablece si se produce un error en la aplicación. Además, el canal WCF puede contener los recuentos de anulaciones de hasta 256 mensajes en la memoria en cualquier momento. Si se lee el mensaje número 257, se restablece el recuento de la anulación del mensaje más antiguo.

Las propiedades de recuento de la anulación y recuento de movimiento están disponibles para la operación del servicio a través del contexto de la operación. En el ejemplo de código siguiente se muestra cómo obtener acceso.

MsmqMessageProperty mqProp = OperationContext.Current.IncomingMessageProperties[MsmqMessageProperty.Name] as MsmqMessageProperty;
Console.WriteLine("Abort count: {0} ", mqProp.AbortCount);
Console.WriteLine("Move count: {0} ", mqProp.MoveCount);
// code to submit purchase order ...

WCF proporciona dos enlaces en cola estándar:

  • NetMsmqBinding. Un enlace de .NET Framework adecuado para realizar comunicaciones basadas en cola con otros puntos de conexión WCF.

  • MsmqIntegrationBinding. Un enlace conveniente para comunicar con aplicaciones Message Queuing existentes.

Nota

Puede modificar las propiedades de estos enlaces en función de los requisitos del servicio WCF. Todo el mecanismo de control de mensajes dudosos es local a la aplicación receptora. El proceso es invisible para la aplicación emisora a menos que la aplicación receptora se detenga finalmente y devuelva una confirmación de que no se pudo realizar la acción al remitente. En ese caso, el mensaje se mueve a la cola de mensajes no enviados del remitente.

Procedimiento recomendado: Controlar MsmqPoisonMessageException

Cuando el servicio determina que un mensaje es dudoso, el transporte en cola arroja MsmqPoisonMessageException que contiene LookupId del mensaje dudoso.

Una aplicación receptora puede implementar la interfaz IErrorHandler para controlar cualquier error que la aplicación requiera. Para obtener más información, consulte Extensión del control sobre el control de errores y los informes.

La aplicación puede requerir algún tipo de control automatizado de mensajes dudosos que los aparte a una cola específica de manera que el servicio pueda tener acceso al resto de los mensajes de la cola. El único escenario para utilizar el mecanismo del controlador de errores para realizar escuchas para las excepciones de mensajes dudosos es cuando ReceiveErrorHandling está establecido en Fault. El ejemplo de mensaje dudoso para Message Queuing 3.0 demuestra este comportamiento. A continuación se dibujan los pasos a realizar para controlar los mensajes dudosos, incluyendo los procedimientos recomendados:

  1. Asegúrese de que la configuración de mensajes dudosos refleja los requisitos de la aplicación. Cuando se trabaja con la configuración, asegúrese de comprender las diferencias entre las funcionalidades de Message Queue Server en Windows Vista, Windows Server 2003 y Windows XP.

  2. En caso de que sea necesario, implemente IErrorHandler para controlar los errores de los mensajes dudosos. Dado que al establecer ReceiveErrorHandling en Fault se requiere un mecanismo manual para quitar el mensaje dudoso de la cola o corregir un problema derivado externo, lo normal es implementar IErrorHandler cuando ReceiveErrorHandling se establece en Fault, como se muestra en el código siguiente.

    class PoisonErrorHandler : IErrorHandler
    {
        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
            // No-op -We are not interested in this. This is only useful if you want to send back a fault on the wire…not applicable for queues [one-way].
        }
    
        public bool HandleError(Exception error)
        {
            if (error != null && error.GetType() == typeof(MsmqPoisonMessageException))
            {
                Console.WriteLine(" Poisoned message -message look up id = {0}", ((MsmqPoisonMessageException)error).MessageLookupId);
                return true;
            }
    
            return false;
        }
    }
    
  3. Cree un PoisonBehaviorAttribute que pueda usar el comportamiento del servicio. El comportamiento instala IErrorHandler en el distribuidor. Vea el ejemplo de código siguiente.

    public class PoisonErrorBehaviorAttribute : Attribute, IServiceBehavior
    {
        Type errorHandlerType;
    
        public PoisonErrorBehaviorAttribute(Type errorHandlerType)
        {
            this.errorHandlerType = errorHandlerType;
        }
    
        void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
        }
    
        void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters)
        {
        }
    
        void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
        {
            IErrorHandler errorHandler;
    
            try
            {
                errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType);
            }
            catch (MissingMethodException e)
            {
                throw new ArgumentException("The errorHandlerType specified in the PoisonErrorBehaviorAttribute constructor must have a public empty constructor", e);
            }
            catch (InvalidCastException e)
            {
                throw new ArgumentException("The errorHandlerType specified in the PoisonErrorBehaviorAttribute constructor must implement System.ServiceModel.Dispatcher.IErrorHandler", e);
            }
    
            foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
            {
                ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
                channelDispatcher.ErrorHandlers.Add(errorHandler);
            }
        }
    }
    
  4. Asegúrese de que su servicio se anote con el atributo de comportamiento de mensajes venenosos.

Además, si ReceiveErrorHandling se establece en Fault, ServiceHost genera un error al encontrar el mensaje dudoso. Puede enlazarlo con el evento que ha generado el error y cerrar el servicio, tomar medidas correctivas y reiniciarlo. Por ejemplo, puede tomar nota del LookupId de la MsmqPoisonMessageException propagada a IErrorHandler y, cuando el host de servicio genere el error, puede utilizar la API System.Messaging para recibir el mensaje de la cola, utilizando el LookupId para quitarlo de la cola y almacenarlo en algún almacén externo u otra cola. Puede reiniciar a continuación ServiceHost para reanudar el procesamiento normal. El control de mensajes dudosos en MSMQ 4.0 muestra este comportamiento.

Tiempo de espera de la transacción y mensajes dudosos

Una clase de errores se puede producir entre el canal de transporte en cola y el código de usuario. Estos errores pueden ser detectados por niveles intermedios, como el nivel de seguridad de mensajes o el servicio que distribuye la lógica. Por ejemplo, cuando se detecta la ausencia de un certificado X.509 en el nivel de seguridad SOAP y la ausencia de una acción son casos en los que el mensaje no se distribuye a la aplicación. Cuando esto sucede, el modelo de servicio quita el mensaje. Puesto que el mensaje se lee en una transacción y no se puede proporcionar un resultado para la misma, la transacción agota el tiempo de espera, se anula y el mensaje se pone de nuevo en la cola. En otras palabras, para una determinada clase de errores, la transacción no se anula de forma inmediata, sino que espera hasta que se agota el tiempo de espera de transacción. Puede modificar el tiempo de espera de transacción para un servicio mediante ServiceBehaviorAttribute.

Para cambiar el tiempo de espera de la transacción en todo el equipo, modifique el archivo machine.config y establezca el tiempo de espera de la transacción adecuado. Es importante tener en cuenta que, en función del tiempo de espera que se establezca en la transacción, la transacción finalmente se anulará y volverá a la cola y su cuenta de anulación se incrementará. Finalmente, el mensaje se convierte en dudoso y se elimina de la forma que especifique la configuración del usuario.

Sesiones y mensajes dudosos

Una sesión sufre los mismos procedimientos de reintento y control de mensajes dudosos como un mensaje único. Las propiedades enumeradas anteriormente para los mensajes dudosos se aplican a toda la sesión. Esto significa que se reintenta la sesión completa y se envía a una cola de mensajes dudosos final o a la cola de mensajes no enviados del remitente si se rechaza el mensaje.

Procesamiento por lotes y mensajes dudosos

Si un mensaje se vuelve un mensaje dudoso y es parte de un lote, se deshace el lote completo y el canal vuelve a leer un mensaje cada vez. Para obtener más información sobre el procesamiento por lotes, consulte Procesamiento por lotes de mensajes en una transacción

Control de mensajes dudosos para mensajes en una cola de mensajes dudosos

El control de mensajes dudosos no finaliza cuando un mensaje se coloca en la cola de mensajes dudosos. Los mensajes de la cola de mensajes dudosos también se deben leer y controlar. Puede utilizar un subconjunto de los valores de control de mensajes dudosos al leer mensajes de la subcola final de mensajes dudosos. La configuración aplicable es ReceiveRetryCount y ReceiveErrorHandling. Puede establecer ReceiveErrorHandling en Drop, Reject o Fault. Se omite MaxRetryCycles y se produce una excepción si ReceiveErrorHandling se establece en Move.

Diferencias entre Windows Vista, Windows Server 2003, y Windows XP

Como se ha señalado anteriormente, no todas las opciones de control de mensajes dudosos se aplican a Windows Server 2003 y Windows XP. Las siguientes diferencias clave entre Message Queue Server en Windows Server 2003, Windows XP y Windows Vista son relevantes para el control de mensajes dudosos:

  • Message Queue Server en Windows Vista admite subcolas, mientras que Windows Server 2003 y Windows XP no lo hacen. Las subcolas se utilizan en el control de mensajes dudosos. Las colas de reintento y la cola dudosa son subcolas en la cola de la aplicación que se crea dependiendo de los valores de control del mensaje dudoso. MaxRetryCycles dicta cuántas subcolas de reintento se crean. Por lo tanto, cuando se ejecutan en Windows Server 2003 o Windows XP, MaxRetryCycles se ignoran y ReceiveErrorHandling.Move no se permite.

  • Message Queue Server en Windows Vista admite la confirmación negativa, mientras que Windows Server 2003 y Windows XP no. Una confirmación de que no se pudo realizar la acción del administrador de la cola receptora hace que el administrador de la cola emisora coloque el mensaje rechazado en la cola de mensajes no enviados. Por tanto, ReceiveErrorHandling.Reject no se permite con Windows Server 2003 ni Windows XP.

  • Message Queue Server en Windows Vista admite una propiedad de mensaje que mantiene un recuento del número de veces que se intenta la entrega del mensaje. Esta propiedad de recuento de anulaciones no está disponible en Windows Server 2003 ni Windows XP. WCF mantiene el recuento de anulaciones en la memoria, por lo que es posible que esta propiedad no contenga un valor preciso cuando más de un servicio WCF lee el mismo mensaje en una granja de servidores.

Consulte también