Tratamento de mensagens suspeitas

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 em fila recebe mensagens sob uma transação. Anular a transação na qual uma mensagem enfileirada foi recebida deixa a mensagem na fila para que a mensagem seja repetida em uma nova transação. Se o problema que causou a transação abortar não for corrigido, o aplicativo recetor pode ficar preso em um loop recebendo e abortando a mesma mensagem até que o número máximo de tentativas de entrega tenha sido excedido e uma mensagem suspeita resulte.

Uma mensagem pode se tornar uma mensagem venenosa por muitos motivos. As razões mais comuns são específicas da aplicação. Por exemplo, se um aplicativo lê uma mensagem de uma fila e executa algum processamento de banco de dados, o aplicativo pode falhar ao obter um bloqueio no banco de dados, fazendo com que ele aborte a transação. Como a transação do 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 venenosas se contiverem informações inválidas. Por exemplo, uma ordem de compra pode conter um número de cliente inválido. Nesses casos, o aplicativo pode abortar voluntariamente a transação e forçar a mensagem a se tornar uma mensagem suspeita.

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

Tratamento de mensagens suspeitas

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

  • ReceiveRetryCount. Um valor inteiro que indica o número máximo de vezes para repetir a 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 com um bloqueio 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 de aplicativos para a subfila de repetição e, após um atraso configurável, da subfila de repetição de volta para a fila de aplicativos para tentar entregar novamente. O valor predefinido é 2. No Windows Vista, a mensagem é tentada no máximo (ReceiveRetryCount +1) * (MaxRetryCycles + 1) vezes. MaxRetryCycles é ignorado no Windows Server 2003 e no Windows XP.

  • RetryCycleDelay. O intervalo de tempo entre os ciclos de repetição. O valor predefinido é 30 minutos. MaxRetryCycles e RetryCycleDelay , em conjunto, fornecem um mecanismo para resolver o problema, em que uma nova tentativa após um atraso periódico corrige o problema. Por exemplo, isso lida com um conjunto de linhas bloqueadas no SQL Server pendente de confirmação de transação.

  • ReceiveErrorHandling. Uma enumeração que indica a ação a ser executada para uma mensagem que falhou na entrega após o número máximo de novas tentativas ter sido tentado. Os valores podem ser Fault, Drop, Reject e Move. A opção padrão é Falha.

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

  • Caia. Esta opção descarta a mensagem suspeita e a mensagem nunca é entregue ao aplicativo. Se a propriedade da TimeToLive mensagem expirou neste momento, a mensagem pode aparecer na fila de mensagens mortas do remetente. Caso contrário, a mensagem não aparece em nenhum lugar. Essa opção indica que o usuário não especificou o que fazer se a mensagem for perdida.

  • Rejeitar. Esta opção está disponível apenas no Windows Vista. Isso instrui o serviço de enfileiramento de mensagens (MSMQ) a enviar uma confirmação negativa de volta 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 de filas de envio.

  • Movimente-se. Esta opção está disponível apenas no Windows Vista. Isso move a mensagem suspeita para uma fila de mensagens suspeitas para processamento posterior por um aplicativo de manipulação de mensagens suspeitas. A fila de mensagens suspeitas é uma subfila da fila de aplicativos. Um aplicativo de manipulação de mensagens suspeitas pode ser um serviço WCF que lê mensagens fora da fila de suspeitas. A fila suspeita é uma subfila da fila de aplicativos e pode ser endereçada como net.msmq://<machine-name>/applicationQueue; poison, onde machine-name é o nome do computador no qual a fila reside e applicationQueue é o nome da fila específica do aplicativo.

A seguir está 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 Windows XP.

Nota

Nenhuma nova tentativa é feita para uma mensagem que é entregue com êxito.

Para controlar o número de vezes que uma mensagem lida é tentada, 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ção que conta o número de vezes que a mensagem se move entre a fila e as subfilas do aplicativo. O canal WCF usa esses para calcular a contagem de repetição de recebimento e a contagem de ciclos de repetição. No Windows Server 2003 e no Windows XP, a contagem de anulação é mantida na memória pelo canal WCF e é redefinida se o aplicativo falhar. Além disso, o canal WCF pode manter as contagens de abortamento para 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 abort count e move count estão disponíveis para a operação de serviço através do contexto da operação. O exemplo de código a seguir mostra como acessá-los.

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 ligações em fila padrão:

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

  • MsmqIntegrationBinding. Uma ligação adequada para comunicação com aplicativos de enfileiramento de mensagens existentes.

Nota

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

Práticas recomendadas: manipulando MsmqPoisonMessageException

Quando o serviço determina que uma mensagem é venenosa, o transporte em fila lança um MsmqPoisonMessageException que contém a LookupId mensagem suspeita.

Um aplicativo de recebimento pode implementar a IErrorHandler interface para lidar com quaisquer erros que o aplicativo exige. Para obter mais informações, consulte Estendendo o controle sobre o tratamento de erros e relatórios.

O aplicativo pode exigir algum tipo de manipulação automatizada de mensagens suspeitas que mova as mensagens suspeitas para uma fila de mensagens suspeitas para que o serviço possa acessar o restante das mensagens na fila. O único cenário para usar o mecanismo manipulador de erros para escutar exceções de mensagens suspeitas é quando a ReceiveErrorHandling configuração está definida como Fault. O exemplo de mensagem suspeita para o serviço de enfileiramento de mensagens 3.0 demonstra esse comportamento. A seguir descrevemos as etapas a serem seguidas para lidar com mensagens suspeitas, incluindo as práticas recomendadas:

  1. Certifique-se de que suas configurações de veneno reflitam os requisitos do seu aplicativo. Ao trabalhar com as configurações, certifique-se de entender as diferenças entre os recursos do serviço de enfileiramento de mensagens no Windows Vista, Windows Server 2003 e Windows XP.

  2. Se necessário, implemente o IErrorHandler para manipular erros de mensagens suspeitas. Como a configuração ReceiveErrorHandling como requer Fault 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 estiver 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 o comportamento de serviço pode usar. O comportamento instala o IErrorHandler no dispatcher. Consulte 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. Certifique-se de que seu serviço esteja anotado com o atributo poison behavior.

Além disso, se o ReceiveErrorHandling estiver definido como Fault, as ServiceHost falhas ao encontrar a mensagem venenosa. Você pode se conectar ao evento com defeito e desligar o serviço, tomar ações corretivas e reiniciar. Por exemplo, o LookupIdMsmqPoisonMessageException no propagado para o IErrorHandler pode ser notado e quando o host de serviço falha, você pode usar a System.Messaging API para receber a mensagem da fila usando o LookupId para remover a mensagem da fila e armazenar a mensagem em algum armazenamento externo ou outra fila. Em seguida, você pode reiniciar ServiceHost para retomar o processamento normal. O tratamento de mensagens suspeitas no MSMQ 4.0 demonstra esse comportamento.

Tempo limite de transação e mensagens suspeitas

Uma classe de erros pode ocorrer entre o canal de transporte enfileirado e o código do usuário. Esses erros podem ser detetados por camadas intermediárias, como a camada de segurança da mensagem ou a lógica de despacho do serviço. Por exemplo, um certificado X.509 ausente detetado 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 descarta 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 eventualmente expira, anula e a mensagem é colocada de volta na fila. Em outras palavras, para uma determinada classe de erros, a transação não aborta imediatamente, mas aguarda até que a transação atinja o tempo limite. Você pode modificar o tempo limite de transação para 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 notar que, dependendo do tempo limite definido na transação, a transação eventualmente aborta e volta para a fila e sua contagem de abortar é incrementada. Eventualmente, a mensagem torna-se venenosa e a disposição correta é feita de acordo com as configurações do usuário.

Sessões e mensagens venenosas

Uma sessão passa pelos mesmos procedimentos de repetição e manipulação de mensagens suspeitas que uma única mensagem. As propriedades listadas anteriormente para mensagens suspeitas aplicam-se 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 for rejeitada.

Lotes e mensagens venenosas

Se uma mensagem se tornar uma mensagem suspeita e fizer parte de um lote, todo o lote será revertido e o canal voltará a ler uma mensagem de cada vez. Para obter mais informações sobre envio em lote, consulte Mensagens em lote em uma transação

Tratamento de mensagens suspeitas para mensagens em uma fila suspeita

O tratamento de mensagens suspeitas não termina quando uma mensagem é colocada na fila de mensagens suspeitas. As mensagens na fila de mensagens suspeitas ainda devem ser lidas e tratadas. Você pode usar um subconjunto das configurações de manipulação de mensagens suspeitas ao ler mensagens da subfila final de mensagens suspeitas. As configurações aplicáveis são ReceiveRetryCount e ReceiveErrorHandling. Você pode definir ReceiveErrorHandling como Soltar, Rejeitar ou Falha. MaxRetryCycles é ignorado e uma exceção é lançada se ReceiveErrorHandling estiver definida como Mover.

Diferenças do Windows Vista, Windows Server 2003 e Windows XP

Como observado anteriormente, nem todas as configurações de manipulação de mensagens suspeitas se aplicam ao Windows Server 2003 e ao Windows XP. As seguintes diferenças principais entre o serviço de enfileiramento de mensagens no Windows Server 2003, Windows XP e Windows Vista são relevantes para o tratamento de mensagens suspeitas:

  • O serviço de enfileiramento de mensagens no Windows Vista oferece suporte a subfilas, enquanto o Windows Server 2003 e o Windows XP não oferecem suporte a subfilas. As subfilas são usadas no tratamento de mensagens suspeitas. As filas de repetição e a fila suspeita são subfilas para a fila de aplicativos criada com base nas configurações de manipulação de mensagens suspeitas. O MaxRetryCycles dita quantas subfilas de repetição devem ser criadas. Portanto, ao executar no Windows Server 2003 ou Windows XP, MaxRetryCycles são ignorados e ReceiveErrorHandling.Move não são permitidos.

  • O serviço de enfileiramento de mensagens no Windows Vista oferece suporte a confirmação negativa, enquanto o Windows Server 2003 e o Windows XP não. 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. Como tal, ReceiveErrorHandling.Reject não é permitido com o Windows Server 2003 e Windows XP.

  • O serviço de enfileiramento de mensagens no Windows Vista oferece suporte a uma propriedade message que mantém a contagem do número de vezes que a entrega de mensagens é tentada. Esta propriedade de contagem de anulação não está disponível no Windows Server 2003 e no Windows XP. O WCF mantém a contagem de anulação na memória, 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.

Consulte também