Share via


Controlar mensajes dudosos

En este tema se describe una manera en que una aplicación que utiliza Service Broker puede detectar un mensaje dudoso y quitar el mensaje de la cola sin confiar en la detección del mensaje dudoso automática.

Service Broker proporciona detección automática de mensajes dudosos. La detección automática de un mensaje dudoso establece el estado de la cola en OFF si una transacción que recibe los mensajes de la cola se revierte cinco veces. Esta característica proporciona una medida de seguridad contra los errores catastróficos que una aplicación no puede detectar mediante programación. Sin embargo, una aplicación no debería confiar en esta característica para el procesamiento normal. Dado que la detección automática del mensaje dudoso detiene la cola, esta característica detiene eficazmente todo el procesamiento de la aplicación hasta que se quite el mensaje dudoso. En su lugar, una aplicación debería intentar detectar y quitar los mensajes dudosos como parte de la lógica de la aplicación.

La estrategia descrita en esta sección supone que se debería quitar un mensaje si se produce un error un determinado número de veces. Para muchas aplicaciones, esta asunción es válida. Sin embargo, antes de utilizar esta estrategia en su aplicación, considere las preguntas siguientes:

  • ¿Es fiable un recuento de errores para su aplicación? Dependiendo de su aplicación, puede ser normal que los mensajes tengan errores de vez en cuando. Por ejemplo, en una aplicación de entrada de órdenes, el servicio que procesa una orden puede tomar menos tiempo de procesamiento que el servicio que agrega un nuevo registro de cliente. En este caso, puede ser normal que no se pueda procesar una orden para un nuevo cliente inmediatamente. La aplicación necesita ser responsable del retraso al decidir si un mensaje es un mensaje dudoso o no. El servicio puede necesitar permitir varios errores antes de quitar el mensaje.

  • ¿Puede su aplicación comprobar rápida y confiablemente el contenido de un mensaje para detectar que nunca puede realizarse correctamente? En ese caso, ésta es una mejor estrategia que contar el número de veces que el programa no procesó el mensaje. Por ejemplo, un informe de gastos que no contiene un nombre de empleado o número de Id. de empleado no se puede procesar. En este caso, el programa puede ser más eficaz si responde inmediatamente a un mensaje que no se puede procesar con un error, en lugar de intentar procesar el mensaje. Considere también otra validación. Por ejemplo, si el número del identificador está presente pero no se encuentra dentro del intervalo de números asignados (por ejemplo, un número negativo), la aplicación puede finalizar inmediatamente la conversación.

  • ¿Debería quitar un mensaje después de un error? Si la aplicación administra un volumen alto de mensajes donde cada mensaje tiene una vida útil limitada, puede ser muy eficaz quitar inmediatamente cualquier mensaje que haga que una operación no se produzca. Por ejemplo, si el mensaje proporciona un informe de progreso del servicio de destino, el servicio iniciador puede elegir descartar un informe de progreso vacío confirmando la recepción sin procesar el mensaje. En este caso, la conversación continúa.

Considere las preguntas siguientes al decidir cómo la aplicación controla un mensaje dudoso:

  • ¿Debe su aplicación registrar el error y el contenido del mensaje? En muchos casos, esto no es necesario. Sin embargo, para algunas aplicaciones, conservar el contenido del mensaje puede ser adecuado.

  • ¿Debe su aplicación registrar otra información sobre el error? En algunos casos, puede desear realizar el seguimiento de otra información sobre la conversación. Por ejemplo, podría utilizar la vista de catálogo sys.conversation_endpoints para identificar la instancia de agente remoto que generó el mensaje dudoso.

  • ¿Su aplicación debería finalizar la conversación con un error o el contrato para el servicio debería permitir a una aplicación indicar un error sin cerrar la conversación? Para muchos servicios, recibir un mensaje dudoso significa que no se puede completar la tarea descrita en el contrato. En este caso, la aplicación finaliza la conversación con un error. En otros casos, la conversación puede continuar aunque un mensaje produzca un error. Por ejemplo, un servicio que recibe los datos del inventario de un almacén de datos puede recibir de vez en cuando un mensaje con un número de pieza desconocido. En lugar de finalizando la conversación, el servicio puede guardar el mensaje en una tabla independiente para que un operador lo inspeccione en un momento posterior.

Ejemplo: Detectar un mensaje dudoso

En este ejemplo de Transact-SQL se muestra un servicio simple, sin estado que incluye la lógica para administrar los mensajes dudosos. Antes de que el procedimiento almacenado reciba un mensaje, el procedimiento guarda la transacción. Cuando el procedimiento no puede procesar un mensaje, el procedimiento revierte la transacción al punto de guardado. La reversión parcial devuelve el mensaje a la cola mientras mantiene un bloqueo en el grupo de conversación del mensaje. Dado que el programa continúa manteniendo el bloqueo del grupo de conversación, el programa puede actualizar una tabla que mantiene una lista de los mensajes que no se ha producido sin que haya riesgo de que otro lector de la cola pueda procesar el mensaje.

En el ejemplo siguiente se define el procedimiento almacenado de activación para la aplicación:

CREATE PROCEDURE ProcessExpenseReport
AS
BEGIN
  WHILE (1 = 1)
    BEGIN
      BEGIN TRANSACTION ;
      DECLARE @conversationHandle UNIQUEIDENTIFIER ;
      DECLARE @messageBody VARBINARY(MAX) ;
      DECLARE @messageTypeName NVARCHAR(256) ;

      SAVE TRANSACTION UndoReceive ;

        WAITFOR ( 
                  RECEIVE TOP(1)
                    @messageTypeName = message_type_name,
                    @messageBody = message_body,
                    @conversationHandle = conversation_handle
                    FROM ExpenseQueue
                 ), TIMEOUT 500 ;

        IF @@ROWCOUNT = 0
        BEGIN
          ROLLBACK TRANSACTION ;
          BREAK ;
        END ;

        -- Typical message processing loop: dispatch to a stored
        -- procedure based on the message type name.  End conversation
        -- with an error for unknown message types.

        -- Process expense report messages. If processing fails,
        -- roll back to the save point and track the failed message.

        IF (@messageTypeName =
              '//Adventure-Works.com/AccountsPayable/ExpenseReport')
          BEGIN
            DECLARE @expenseReport NVARCHAR(MAX) ;
            SET @expenseReport = CAST(@messageBody AS NVARCHAR(MAX)) ;
            EXEC AdventureWorks.dbo.AddExpenseReport
              @report = @expenseReport ;
            IF @@ERROR <> 0
             BEGIN
               ROLLBACK TRANSACTION UndoReceive ;
               EXEC TrackMessage @conversationHandle ;
             END ;
            ELSE
             BEGIN
               EXEC AdventureWorks.dbo.ClearMessageTracking
                 @conversationHandle ;
             END ;
           END ;
        ELSE

        -- For error messages and end dialog messages, end the
        -- conversation.

        IF (@messageTypeName =
              'https://schemas.microsoft.com/SQL/ServiceBroker/Error' OR
             @messageTypeName =
              'https://schemas.microsoft.com/SQL/ServiceBroker/EndDialog')
          BEGIN
            END CONVERSATION @conversationHandle ;
            EXEC dbo.ClearMessageTracking @conversationHandle ;
          END ;


         COMMIT TRANSACTION ;
    END ;
END ;

El procedimiento almacenado TrackMessage realiza el seguimiento del número de veces que no se ha producido un mensaje. Si no se ha producido un error en el mensaje antes, el procedimiento inserta un nuevo contador para el mensaje en la tabla ExpenseServiceFailedMessages. De lo contrario, el procedimiento comprueba el número de veces que el mensaje produjo un error. El procedimiento incrementa el contador cuando éste es menor que un número predefinido. Cuando el contador es mayor que el número predefinido, el procedimiento finaliza la conversación con un error y quita el contador para la conversación de la tabla.

CREATE PROCEDURE TrackMessage
@conversationHandle uniqueidentifier
AS
BEGIN
  IF @conversationHandle IS NULL
    RETURN ;

  DECLARE @count INT ;
  SET @count = NULL ;
  SET @count = (SELECT count FROM dbo.ExpenseServiceFailedMessages
                  WHERE conversation_handle = @conversationHandle) ;

  IF @count IS NULL
    BEGIN
      INSERT INTO dbo.ExpenseServiceFailedMessages
        (count, conversation_handle)
        VALUES (1, @conversationHandle) ;
    END ;
  IF @count > 3
    BEGIN
      EXEC dbo.ClearMessageTracking @conversationHandle ;
      END CONVERSATION @conversationHandle
        WITH ERROR = 500
        DESCRIPTION = 'Unable to process message.' ;
    END ;
  ELSE
    BEGIN
      UPDATE dbo.ExpenseServiceFailedMessages
        SET count=count+1
        WHERE conversation_handle = @conversationHandle ;
    END ;
END ;
GO

La definición de la tabla ExpenseServiceFailedMessages simplemente contiene una columna conversation_handle y una columna count, como se muestra en el ejemplo siguiente:

CREATE TABLE ExpenseServiceFailedMessages (
  conversation_handle uniqueidentifier PRIMARY KEY,
  count smallint
) ;

El procedimiento ClearMessageTracking elimina el contador para una conversación de la tabla ExpenseServiceFailedMessages, como se muestra en el ejemplo siguiente:

CREATE PROCEDURE ClearMessageTracking
  @conversationHandle uniqueidentifier
AS
BEGIN
   DELETE FROM dbo.ExpenseServiceFailedMessages
     WHERE conversation_handle = @conversationHandle ;
END ;
GO

La estrategia que se muestra aquí es deliberadamente sencilla. Debería utilizar las ideas en este tema como una base para generar una aplicación que coincida con sus necesidades. Por ejemplo, si su aplicación mantiene el estado, puede ser más eficaz incluir la información de seguimiento para los mensajes no producidos en las tablas de estado de la aplicación.

Los procedimientos almacenados anteriores no controlan los errores que harían que una transacción no se produjera. Si este servicio recibe un mensaje que hace que la transacción completa no se produzca, la transacción se revertirá. Si esto sucede cinco veces, la detección del mensaje dudoso automática establecerá el estado de la cola en OFF. En este caso, un administrador debe quitar el mensaje dudoso o se debe utilizar una aplicación diferente para esta acción.

Si cree que el procesamiento que realiza en el mensaje podría producir un error de la transacción, puede utilizar las instrucciones CATCH y TRY para controlar el error. Para obtener más información sobre cómo controlar errores, vea Controlar errores del motor de base de datos.