Compartilhar via


Manuseio de mensagem suspeita

Uma mensagem suspeita é uma mensagem que excedeu o número máximo de tentativas de entrega para o aplicativo. Essa situação pode surgir quando um aplicativo baseado em fila não pode processar uma mensagem devido a erros. Para atender às demandas de confiabilidade, um aplicativo na fila recebe mensagens em uma transação. Anular a transação na qual uma mensagem na fila foi recebida deixa a mensagem na fila para que a mensagem seja repetida em uma nova transação. Se o problema que causou a anulação da transação não for corrigido, o aplicativo de recebimento poderá ficar preso em um loop de recebimento e anulação da mesma mensagem, até que o número máximo de tentativas de entrega seja excedido e uma mensagem suspeita seja exibida como resultado.

Uma mensagem pode se tornar uma mensagem suspeita por várias razões. Os motivos mais comuns são específicos do aplicativo. Por exemplo, se um aplicativo ler uma mensagem de uma fila e executar um processamento de banco de dados, o aplicativo poderá não conseguir obter um bloqueio no banco de dados, fazendo com que ele anule a transação. Como a transação de banco de dados foi anulada, a mensagem permanece na fila, o que faz com que o aplicativo releia a mensagem uma segunda vez e faça outra tentativa de adquirir um bloqueio no banco de dados. As mensagens também podem se tornar suspeitas se contêm informações inválidas. Por exemplo, uma ordem de compra pode conter um número de cliente inválido. Nesses casos, o aplicativo pode anular voluntariamente a transação e forçar a mensagem a se tornar uma mensagem suspeita.

Em raras ocasiões, as mensagens podem falhar ao serem enviadas para o aplicativo. A camada do WCF (Windows Communication Foundation) pode encontrar um problema com a mensagem, como se a mensagem tivesse o quadro errado, credenciais de mensagem inválidas anexadas ou um cabeçalho de ação inválido. Nesses casos, o aplicativo nunca recebe a mensagem. No entanto, a mensagem ainda pode se tornar uma mensagem suspeita e ser processada manualmente.

Tratando de mensagens suspeitas

No WCF, o tratamento de mensagens suspeitas fornece um mecanismo para um aplicativo de recebimento lidar com mensagens que não possam ser expedidas para o aplicativo ou com mensagens expedidas para o aplicativo, mas que não são processadas por motivos específicos do aplicativo. Configure o tratamento de mensagens suspeitas com as seguintes propriedades em cada uma das associações na fila disponíveis:

  • ReceiveRetryCount. Um valor inteiro que indica o número máximo de vezes de repetições de entrega de uma mensagem da fila do aplicativo para o aplicativo. O valor padrão é 5. Isso é suficiente nos casos em que uma nova tentativa imediata corrige o problema, como ocorre com um deadlock temporário em um banco de dados.

  • MaxRetryCycles. Um valor inteiro que indica o número máximo de ciclos de repetição. Um ciclo de repetição consiste em transferir uma mensagem da fila do aplicativo para a subconsulta de repetição e, após um atraso configurável, da subconsulta de repetição novamente para a fila do aplicativo a fim de fazer uma nova tentativa de entrega. O valor padrão é 2. No Windows Vista, é feita, no máximo, (ReceiveRetryCount +1) * (MaxRetryCycles + 1) vezes de tentativa de entrega da mensagem. MaxRetryCycles é ignorado no Windows Server 2003 e no Windows XP.

  • RetryCycleDelay. O atraso de tempo entre os ciclos de repetição. O valor padrão é de 30 minutos. MaxRetryCycles e RetryCycleDelay, juntos, fornecem um mecanismo para resolver o problema em que uma repetição após um atraso periódico corrige o problema. Por exemplo, isso trata um conjunto de linhas bloqueado na confirmação de transação pendente do SQL Server.

  • ReceiveErrorHandling. Uma enumeração que indica a ação a ser executada para uma mensagem que não foi entregue depois que o número máximo de tentativas foi feito. Os valores podem ser Falha, Remover, Rejeitar e Mover. A opção padrão é Falha.

  • Falha. Essa opção envia uma falha para o ouvinte que causou a falha do ServiceHost. A mensagem deve ser removida da fila de aplicativos por algum mecanismo externo antes que o aplicativo possa continuar a processar mensagens da fila.

  • Drop. Essa opção remove a mensagem suspeita, e a mensagem nunca é entregue ao aplicativo. Se a propriedade TimeToLive da mensagem venceu neste ponto, a mensagem pode ser exibida na fila de mensagens mortas do remetente. Caso contrário, a mensagem não aparecerá em lugar nenhum. Essa opção indica que o usuário não especificou o que fazer se a mensagem for perdida.

  • Rejeitar. Essa opção só está disponível no Windows Vista. Isso instrui o MSMQ (Enfileiramento de Mensagens) a enviar uma confirmação negativa novamente ao gerenciador de filas de envio de que o aplicativo não pode receber a mensagem. A mensagem é colocada na fila de mensagens mortas do gerenciador da fila de envio.

  • Mover. Essa opção só está disponível no Windows Vista. Isso move a mensagem suspeita para uma fila de mensagens suspeitas para processamento posterior por um aplicativo de tratamento de mensagens suspeitas. A fila de mensagens suspeitas é uma subconsulta da fila do aplicativo. Um aplicativo de tratamento de mensagens suspeitas pode ser um serviço WCF que lê mensagens da fila de mensagens suspeitas. A fila de mensagens suspeitas é uma subconsulta da fila do aplicativo e pode ser tratada como net.msmq://<machine-name>/applicationQueue;poison, em que machine-name é o nome do computador no qual a fila se encontra e applicationQueue é o nome da fila específica do aplicativo.

Veja abaixo o número máximo de tentativas de entrega feitas para uma mensagem:

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

  • (ReceiveRetryCount + 1) no Windows Server 2003 e no Windows XP.

Observação

Não são feitas novas tentativas para uma mensagem entregue com sucesso.

Para acompanhar o número de vezes que é feita a tentativa de leitura de uma mensagem, o Windows Vista mantém uma propriedade de mensagem durável que conta o número de anulações e uma propriedade de contagem de movimentações que conta o número de vezes que a mensagem se move entre a fila do aplicativo e as subconsultas. O canal do WCF usa-as para calcular a contagem de repetições de recebimento e a contagem de ciclos de repetição. No Windows Server 2003 e no Windows XP, a contagem de anulações é mantida na memória pelo canal do WCF e é redefinida em caso de falha do aplicativo. Além disso, o canal do WCF pode conter as contagens de anulações de até 256 mensagens na memória a qualquer momento. Se uma 257ª mensagem for lida, a contagem de anulações da mensagem mais antiga será redefinida.

As propriedades de contagem de anulações e de contagem de movimentações estão disponíveis para a operação de serviço por meio do contexto de operação. O exemplo de código a seguir mostra como acessá-las.

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 ...

O WCF fornece duas associações de fila padrão:

  • NetMsmqBinding. Uma associação do .NET Framework adequada para executar a comunicação baseada em fila com outros pontos de extremidade do WCF.

  • MsmqIntegrationBinding. Uma associação adequada para se comunicar com os aplicativos de enfileiramento de mensagens existentes.

Observação

Você pode alterar as propriedades nessas associações com base nos requisitos do serviço WCF. Todo o mecanismo de tratamento de mensagens suspeitas é local para o aplicativo de recebimento. O processo é invisível para o aplicativo de envio, a menos que o aplicativo de recebimento pare e envie uma confirmação negativa novamente para o remetente. Nesse caso, a mensagem é movida para a fila de mensagens mortas do remetente.

Melhor prática: tratamento de MsmqPoisonMessageException

Quando o serviço determina que uma mensagem é suspeita, o transporte na fila gera uma MsmqPoisonMessageException que contém a LookupId da mensagem suspeita.

Um aplicativo de recebimento pode implementar a interface IErrorHandler para tratar os erros necessários para o aplicativo. Para obter mais informações, confira Como estender o controle sobre o tratamento de erros e os relatórios.

O aplicativo pode exigir algum tipo de tratamento automatizado de mensagens suspeitas que move as mensagens suspeitas para uma fila de mensagens suspeitas, de modo que o serviço possa acessar o restante das mensagens na fila. O único cenário de uso do mecanismo de tratamento de erros para escutar exceções de mensagens suspeitas é quando a configuração ReceiveErrorHandling é definida como Fault. O exemplo de mensagem suspeita do Enfileiramento de Mensagens 3.0 demonstra esse comportamento. Estas são as etapas a serem executadas para lidar com mensagens suspeitas, incluindo as melhores práticas:

  1. Verifique se as configurações de mensagens suspeitas refletem os requisitos do aplicativo. Ao trabalhar com as configurações, verifique se você entende as diferenças entre as funcionalidades do Enfileiramento de Mensagens no Windows Vista, no Windows Server 2003 e no Windows XP.

  2. Se necessário, implemente o IErrorHandler para tratar os erros de mensagens suspeitas. Como a configuração de ReceiveErrorHandling como Fault exige um mecanismo manual para mover a mensagem suspeita para fora da fila ou para corrigir um problema dependente externo, o uso típico é implementar IErrorHandler quando ReceiveErrorHandling está definido como Fault, conforme mostrado no código a seguir.

    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. Crie um PoisonBehaviorAttribute que possa ser usado pelo comportamento do serviço. O comportamento instala o IErrorHandler no dispatcher. Confira o exemplo de código a seguir.

    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. Verifique se o serviço está anotado com o atributo de comportamento suspeito.

Além disso, se o ReceiveErrorHandling estiver definido como Fault, o ServiceHost causará uma falha ao encontrar a mensagem suspeita. Você pode se conectar ao evento com falha e desligar o serviço, executar ações corretivas e reiniciá-lo. Por exemplo, a LookupId na MsmqPoisonMessageException propagada para o IErrorHandler pode ser observada e, quando o host de serviço falha, você pode usar a API System.Messaging para receber a mensagem da fila usando a LookupId para remover a mensagem da fila e armazená-la em um repositório externo ou em outra fila. Você pode reiniciar o ServiceHost para retomar o processamento normal. O tratamento de mensagens suspeitas no MSMQ 4.0 demonstra esse comportamento.

Tempo limite de transações e mensagens suspeitas

Uma classe de erros pode ocorrer entre o canal de transporte na fila e o código do usuário. Esses erros podem ser detectados pelas camadas intermediárias, como a camada de segurança da mensagem ou a lógica de expedição de serviço. Por exemplo, um certificado X.509 ausente detectado na camada de segurança SOAP e uma ação ausente são casos em que a mensagem é enviada para o aplicativo. Quando isso acontece, o modelo de serviço remove a mensagem. Como a mensagem é lida em uma transação e um resultado para essa transação não pode ser fornecido, a transação acaba atingindo o tempo limite e é anulada, e a mensagem é colocada novamente na fila. Em outras palavras, para uma classe específica de erros, a transação não é anulada imediatamente, mas aguarda até o tempo limite da transação. Você pode modificar o tempo limite da transação de um serviço usando ServiceBehaviorAttribute.

Para alterar o tempo limite da transação em todo o computador, modifique o arquivo machine.config e defina o tempo limite de transação apropriado. É importante observar que, dependendo do tempo limite definido na transação, a transação acaba sendo anulada e volta à fila, e a contagem de anulações é incrementada. Por fim, a mensagem se torna suspeita e a disposição certa é feita de acordo com as configurações do usuário.

Sessões e mensagens suspeitas

Uma sessão passa pelos mesmos procedimentos de repetição e tratamento de mensagens suspeitas de uma mensagem individual. As propriedades listadas anteriormente para mensagens suspeitas se aplicam a toda a sessão. Isso significa que toda a sessão é repetida e vai para uma fila final de mensagens suspeitas ou para a fila de mensagens mortas do remetente se a mensagem é rejeitada.

Envio em lote e mensagens suspeitas

Se uma mensagem se tornar uma mensagem suspeita e fizer parte de um lote, todo o lote será revertido e o canal retornará para ler uma mensagem de cada vez. Para obter mais informações sobre o envio em lote, confira Como enviar mensagens em lote em uma transação

Tratamento de mensagens suspeitas em uma fila de mensagens suspeitas

O tratamento de mensagens suspeitas não termina quando uma mensagem é colocada na fila de mensagens suspeitas. As mensagens da fila de mensagens suspeitas ainda precisam ser lidas e tratadas. Você pode usar um subconjunto das configurações de tratamento de mensagens suspeitas ao ler as mensagens da subconsulta final de mensagens suspeitas. As configurações aplicáveis são ReceiveRetryCount e ReceiveErrorHandling. Você pode definir ReceiveErrorHandling como Remover, Rejeitar ou Falha. MaxRetryCycles é ignorado, e uma exceção é gerada se ReceiveErrorHandling está definido como Mover.

Diferenças entre o Windows Vista, o Windows Server 2003 e o Windows XP

Como já indicado, nem todas as configurações de tratamento de mensagens suspeitas se aplicam ao Windows Server 2003 e ao Windows XP. As principais diferenças entre o Enfileiramento de Mensagens no Windows Server 2003, no Windows XP e no Windows Vista são relevantes para o tratamento de mensagens suspeitas:

  • O Enfileiramento de Mensagens no Windows Vista dá suporte a subconsultas, enquanto o Windows Server 2003 e o Windows XP não dão suporte a subconsultas. As subfilas são usadas no tratamento de mensagens suspeitas. As filas de repetição e a fila de mensagens suspeitas são subfilas da fila do aplicativo que é criada com base nas configurações de tratamento de mensagens suspeitas. O MaxRetryCycles determina quantas subconsultas de repetição serão criadas. Portanto, ao ser executado no Windows Server 2003 ou no Windows XP, MaxRetryCycles são ignorados e ReceiveErrorHandling.Move não são permitidos.

  • O Enfileiramento de Mensagens no Windows Vista dá suporte à confirmação negativa, ao contrário do Windows Server 2003 e do Windows XP. Uma confirmação negativa do gerenciador de filas de recebimento faz com que o gerenciador de filas de envio coloque a mensagem rejeitada na fila de mensagens mortas. Dessa forma, ReceiveErrorHandling.Reject não é permitido no Windows Server 2003 e no Windows XP.

  • O Enfileiramento de Mensagens no Windows Vista dá suporte a uma propriedade de mensagem que mantém a contagem do número de tentativas de entrega das mensagens. Essa propriedade de contagem de anulações não está disponível no Windows Server 2003 e no Windows XP. O WCF mantém a contagem de anulações na memória, sendo, portanto, possível que essa propriedade não contenha um valor preciso quando a mesma mensagem é lida por mais de um serviço WCF em um farm.

Confira também