Обработка подозрительных сообщений

Отравляющее сообщение — это сообщение, превышающее максимальное количество попыток доставки приложению. Такая ситуация может возникнуть, если приложение с очередью не может обработать сообщение из-за ошибок. Чтобы отвечать требованиям надежности, приложение с очередью получает сообщения транзакционно. Прерывание транзакции, в которой получено очередное сообщение, приводит к тому, что сообщение остается в очереди и новая попытка доставить его предпринимается в новой транзакции. Если причина прерывания транзакции не устранена, принимающее приложение может зациклиться, получая и прерывая прием одного и того же сообщения, до достижения максимального числа попыток доставки и пометки сообщения как подозрительного.

Сообщение может стать подозрительным по многим причинам. Наиболее распространенными причинами являются приложения. Например, если приложение читает сообщение из очереди и выполняет определенную обработку базы данных, приложение может потерпеть неудачу при попытке заблокировать базу данных и транзакция будет прервана. Из-за прерывания транзакции базы данных сообщение остается в очереди, поэтому приложение повторно читает сообщение и делает попытку заблокировать базу данных. Сообщения также могут быть подозрительными, если они содержат недопустимую информацию. Например, заказ на покупку может содержать недопустимый номер заказчика. В таких случаях приложение может по своему выбору прервать транзакцию и пометить сообщение как подозрительное.

В редких случаях не удается отправить сообщения приложению. Слой Windows Communication Foundation (WCF) может найти проблему с сообщением, например, если сообщение имеет неправильный кадр, недопустимые учетные данные сообщения, подключенные к нему, или недопустимый заголовок действия. В таких случаях приложение не получает сообщение. Однако сообщение все еще может превратиться в подозрительное и быть обработано вручную.

Обработка подозрительных сообщений

В WCF обработка отравляющих сообщений предоставляет механизм для получения приложения для работы с сообщениями, которые не могут быть отправлены в приложение или сообщения, отправленные в приложение, но которые не обрабатываются из-за конкретных причин приложения. Настройте обработку подозрительных сообщений со следующими свойствами в каждой из доступных привязок очереди:

  • ReceiveRetryCount. Целое значение, указывающее максимальное число повторных попыток доставить сообщение из очереди приложения в приложение. Значение по умолчанию равно 5. Это важно в тех случаях, когда немедленная повторная попытка решает проблему, например проблему со временной взаимоблокировкой в базе данных.

  • MaxRetryCycles. Целое значение, указывающее максимальное число циклов повторных попыток. Цикл повторной попытки состоит из передачи сообщения из очереди приложения во вложенную очередь повторной отправки и, через настраиваемый промежуток времени, передачи из вложенной очереди повторной отправки обратно в очередь приложения для новой попытки доставки. Значение по умолчанию равно 2. В Windows Vista сообщение выполняется не более (ReceiveRetryCount +1) * (MaxRetryCycles + 1) раз. MaxRetryCycles игнорируется в Windows Server 2003 и Windows XP.

  • RetryCycleDelay. Промежуток времени между циклами повторных попыток. Значение по умолчанию составляет 30 минут. MaxRetryCycles и RetryCycleDelay вместе реализуют механизм устранения проблемы, решением которой может быть повторная попытка доставки сообщения с периодической задержкой. Например, это помогает для блокированного набора строк при отложенном завершении транзакции в SQL Server.

  • ReceiveErrorHandling. Перечисление, указывающее, какое действие выполняется для сообщения, доставка которого не удалась после максимального числа повторных попыток. Возможные значения: Fault, Drop, Reject и Move. Значение по умолчанию - Fault.

  • Fault. Отправляется ошибка прослушивателю, который привел к сбою ServiceHost. Сообщение должно быть удалено из очереди приложения при помощи внешнего механизма, прежде чем приложение сможет продолжить обрабатывать сообщения очереди.

  • Drop. Подозрительное сообщение отбрасывается и никогда не будет доставлено в приложение. Если к этому моменту время, заданное свойством TimeToLive сообщения, истекло, сообщение может появиться в очереди недоставленных сообщений отправителя. Если не истекло, сообщение нигде не появляется. Этот вариант означает, что пользователь не позаботился о том, что должно произойти в случае потери сообщения.

  • Reject. Этот параметр доступен только в Windows Vista. Это указывает очереди сообщений (MSMQ) отправить отрицательное подтверждение обратно диспетчеру очередей отправки, что приложение не может получить сообщение. Сообщение помещается в очередь недоставленных сообщений диспетчера передающей очереди.

  • Переместить... Этот параметр доступен только в Windows Vista. Подозрительное сообщение перемещается в очередь подозрительных сообщений для дальнейшей обработки приложением по работе с подозрительными сообщениями. Очередь подозрительных сообщений является вложенной очередью очереди приложения. Приложение для обработки подозрительных сообщений может быть службой WCF, которая считывает сообщения из очереди ядов. Очередь яда является вложенным запросом очереди приложения и может быть устранена как net.msmq://<machine-name>/applicationQueue; poison, где имя компьютера — это имя компьютера, на котором находится очередь, а приложениеQueue — это имя очереди для конкретного приложения.

Далее приведены максимальные числа попыток доставки для сообщения.

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

  • (ReceiveRetryCount + 1) в Windows Server 2003 и Windows XP.

Примечание.

Для успешно доставленного сообщения повторных попыток доставки не выполняется.

Чтобы отслеживать количество попыток чтения сообщения, Windows Vista поддерживает свойство устойчивого сообщения, которое подсчитывает количество прерываний и свойство счетчика перемещения, которое подсчитывает количество перемещений сообщения между очередью приложения и вложенными запросами. Канал WCF использует их для вычисления счетчика повторных попыток получения и количества циклов повторных попыток. В Windows Server 2003 и Windows XP количество прерываний сохраняется в памяти каналом WCF и сбрасывается, если приложение завершается ошибкой. Кроме того, канал WCF может содержать количество прерываний до 256 сообщений в памяти в любое время. Когда прочитывается 257-е сообщение, подсчет числа прекращений для самого старого сообщения сбрасывается.

Свойства подсчета прекращений и перемещений доступны для операции службы через контекст операции. В следующем примере кода представлен способ обращения к ним.

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 предоставляет две стандартные привязки с очередями:

  • NetMsmqBinding. Привязка платформа .NET Framework, подходящая для выполнения связи на основе очередей с другими конечными точками WCF.

  • MsmqIntegrationBinding. Привязка, подходящая для взаимодействия с существующими приложениями MSMQ.

Примечание.

Вы можете изменить свойства в этих привязках на основе требований службы WCF. Весь механизм обработки подозрительных сообщений является локальным для принимающего приложения. Этот процесс невидим для отправляющего приложения, если только принимающее приложение не останавливается и не посылает отправителю уведомление о недоставке. В таком случае сообщение перемещается в очередь недоставленных сообщений отправителя.

Рекомендации. Обработка исключения MsmqPoisonMessageException

Когда служба определяет, что сообщение подозрительно, транспорт очереди создает исключение MsmqPoisonMessageException, содержащее LookupId подозрительного сообщения.

Принимающее приложение может реализовывать интерфейс IErrorHandler для обработки всех необходимых ошибок. Дополнительные сведения см. в разделе "Расширение управления обработкой ошибок" и "Отчеты".

Приложению может требоваться определенная автоматическая обработка подозрительных сообщений, перемещающая подозрительные сообщения в очередь подозрительных сообщений, чтобы служба могла получить доступ к оставшимся сообщениям в очереди. Использование механизма обработчика ошибок для ожидания возникновения исключений, связанных с подозрительными сообщениями, возможно только если параметр ReceiveErrorHandling имеет значение Fault. Пример подозрительного сообщения для MSMQ 3.0 иллюстрирует такое поведение. Далее описаны основные шаги, которые необходимо предпринять для обработки подозрительных сообщений, также даны рекомендации.

  1. Убедитесь, что параметры, заданные для подозрительных сообщений, отражают требования приложения. При работе с параметрами убедитесь, что вы понимаете различия между возможностями очереди сообщений в Windows Vista, Windows Server 2003 и Windows XP.

  2. При необходимости реализуйте обработку IErrorHandler ошибок с сообщением о яд- сообщении. Поскольку, если задать для свойства ReceiveErrorHandling значение Fault, потребуется ручной механизм для перемещения подозрительного сообщения из очереди или для исправления проблем, связанных со внешними обстоятельствами, стандартное использование - реализация IErrorHandler со значением ReceiveErrorHandling свойства Fault, как показано в следующем коде.

    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. Создайте атрибут PoisonBehaviorAttribute, который сможет использовать поведение службы. Поведение устанавливает IErrorHandler в диспетчере. См. следующий пример кода.

    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. Убедитесь, что служба помечена атрибутом PoisonBehaviorAttribute.

Кроме того, если свойство ReceiveErrorHandling имеет значение Fault, ServiceHost завершает работу с ошибкой, если встречает подозрительное сообщение. Можно подключиться к событию с ошибкой и завершить работу службы, предпринять действия по исправлению ошибки и перезапустить службу. Например, LookupId в исключении MsmqPoisonMessageException, распространенный на объект IErrorHandler, может запоминаться, и когда узел службы завершает работу с ошибкой, можно использовать API System.Messaging для получения сообщения из очереди с помощью LookupId, чтобы удалить сообщение из очереди и сохранить его во внешнем хранилище или другой очереди. Затем можно перезапустить ServiceHost, чтобы возобновить нормальную работу. Обработка подозрительных сообщений в MSMQ 4.0 демонстрирует это поведение.

Время ожидания транзакции и подозрительные сообщения

Между транспортным каналом очереди и пользовательским кодом может возникнуть класс ошибок. Эти ошибки могут быть обнаружены промежуточными уровнями, например уровнем безопасности сообщений или логикой отправки службы. Например, отсутствие сертификата X.509, обнаруженное на уровне безопасности SOAP, и отсутствие действия - случаи отправки сообщения приложению. Когда возникает такая ситуация, модель службы отбрасывает сообщение. Так как чтение сообщения происходит в транзакции и результат транзакции не может быт получен, время ожидания транзакции истекает, транзакция прерывается и сообщение помещается обратно в очередь. Другими словами, для определенного класса ошибок транзакция не сразу прерывается, но ожидает, пока транзакция не истекает. Вы можете изменить время ожидания транзакции для службы с помощью ServiceBehaviorAttribute.

Чтобы изменить время ожидания транзакции на уровне компьютера, измените файл конфигурации machine.config и задайте соответствующее время ожидания транзакции. Важно отметить, что в зависимости от времени ожидания, заданного в транзакции, транзакция в конечном итоге прерывается и возвращается в очередь, а его количество прерываний увеличивается. В итоге сообщение становится подозрительным и предпринимаются действия в соответствии с параметрами пользователя.

Сеансы и подозрительные сообщения

Сеанс проходит те же процедуры повторных попыток и обработки подозрительных сообщений, что и отдельное сообщение. Свойства, перечисленные ранее для подозрительных сообщений, применимы и к целому сеансу. Это значит, что происходит повторная попытка выполнения сеанса целиком, и он перемещается в конечную очередь подозрительных сообщений или очередь недоставленных сообщений отправителя, если сообщение не принято.

Пакетирование и подозрительные сообщения

Если сообщение о сбое становится подозрительным и представляет собой часть пакета, весь пакет откатывается и канал возвращается к чтению сообщений по одному. Дополнительные сведения о пакетной обработке см. в разделе "Пакетные сообщения" в транзакции

Обработка подозрительных сообщений из очереди подозрительных сообщений

Обработка подозрительного сообщения не заканчивается его перемещением в очередь подозрительных сообщений. Сообщения из очереди подозрительных сообщений по прежнему должны прочитываться и обрабатываться. При чтении сообщений из конечной вложенной очереди подозрительных сообщений можно использовать подмножество параметров обработки подозрительных сообщений. Применимые параметры: ReceiveRetryCount и ReceiveErrorHandling. ReceiveErrorHandling можно установить в значение Drop, Reject или Fault. MaxRetryCycles не обрабатывает исключение, если параметр ReceiveErrorHandling установлен в значение Move.

Различия Windows Vista, Windows Server 2003 и Windows XP

Как отмечалось ранее, к Windows Server 2003 и Windows XP применяются не все параметры обработки сообщений с подозрительными сообщениями. Следующие ключевые различия между очередью сообщений в Windows Server 2003, Windows XP и Windows Vista относятся к обработке подозрительных сообщений:

  • Очередь сообщений в Windows Vista поддерживает вложенные запросы, а Windows Server 2003 и Windows XP не поддерживают вложенные запросы. Вложенные очереди используются при обработке подозрительных сообщений. Очереди повторных попыток и очередь подозрительных сообщений являются вложенными очередями очереди приложения, созданной на основе параметров обработки подозрительных сообщений. Значение MaxRetryCycles указывает, сколько необходимо создать вложенных очередей повторных попыток. Поэтому при запуске в Windows Server 2003 или Windows XP MaxRetryCycles игнорируются и ReceiveErrorHandling.Move не допускаются.

  • Очередь сообщений в Windows Vista поддерживает отрицательное подтверждение, а Windows Server 2003 и Windows XP не поддерживают. Уведомление о недоставке от диспетчера принимающей очереди приводит к тому, что диспетчер передающей очереди помещает сообщение в очередь недоставленных сообщений. Таким образом, ReceiveErrorHandling.Reject запрещено использовать Windows Server 2003 и Windows XP.

  • Очередь сообщений в Windows Vista поддерживает свойство сообщения, которое сохраняет количество попыток доставки сообщений. Это свойство прерывания недоступно в Windows Server 2003 и Windows XP. WCF поддерживает количество прерываний в памяти, поэтому возможно, что это свойство не может содержать точное значение, если одно сообщение считывается несколькими службами WCF в ферме.

См. также