Подтвердить что ты не робот

Как обрабатывать сбой сообщений в привязках MSMQ для WCF

Я создал службу WCF и использую привязку netMsmqBinding.

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

Каков наилучший способ убедиться, что данные не теряются.

Я пробовал два следующих метода:

  • Выбросить исключение

    Это помещает сообщение в очередь с мертвой буквой для ручного прочтения. Я могу обработать это, когда начинается strvice

  • установите значение receiveRetryCount = "3" для привязки

    После 3 попыток - которые происходят мгновенно, это, похоже, оставляет сообщение в очереди, но вызывает ошибку. Перезапуск службы повторяет этот процесс.

В идеале я хотел бы сделать следующее:

Попробуйте обработать сообщение

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

Могу ли я достичь этого? Если да, то как? Можете ли вы указать мне на какие-либо хорошие статьи о том, как лучше всего использовать WCF и MSMQ для моих данных сцен.

Любая помощь будет высоко оценена. Спасибо!

Дополнительная информация

Я использую MSMQ 3.0 в Windows XP и Windows Server 2003. К сожалению, я не могу использовать встроенную поддержку ядовитых сообщений, ориентированную на MSMQ 4.0 и Vista/2008.

4b9b3361

Ответ 1

Вот пример в SDK, который может быть полезен в вашем случае. В основном, то, что он делает, это привязать реализацию IErrorHandler к вашей службе, которая поймает ошибку, когда WCF объявит сообщение "ядом" (т.е. Когда все настроенные попытки были исчерпаны). То, что делает образец, переводит сообщение в другую очередь, а затем перезапускает ServiceHost, связанную с сообщением (поскольку он будет сбой при обнаружении ядовитого сообщения).

Это не очень хороший образец, но он может быть полезен. Однако есть несколько ограничений:

1- Если у вас несколько конечных точек, связанных с вашей службой (т.е. через несколько очередей), нет способа узнать, в какую очередь попало ядовитое сообщение. Если у вас только одна очередь, это не будет проблемой, Я не видел официального обходного пути для этого, но я экспериментировал с одной возможной альтернативой, которую я документировал здесь: http://winterdom.com/weblog/2008/05/27/NetMSMQAndPoisonMessages.aspx

2- Как только сообщение проблемы перемещается в другую очередь, оно становится вашей ответственностью, поэтому вам нужно переместить его обратно в очередь обработки после завершения таймаута (или подключить новую службу к этой очереди для ее обработки).

Если честно, в любом случае вы смотрите на какую-то "ручную" работу здесь, когда WCF просто не накрывает ее.

Недавно я работал над другим проектом, в котором у меня есть требование явно контролировать, как часто повторяются попытки, и моим текущим решением было создать набор очередей повторных попыток и вручную переместить сообщения между очередями повтора и основной обработкой очередь на основе набора таймеров и некоторых эвристик, просто используя необработанные элементы System.Messaging для обработки очередей MSMQ. Кажется, что это работает очень хорошо, хотя есть несколько ошибок, если вы идете этим путем.

Ответ 2

Я думаю, что с MSMQ (доступным только для Vista) вы могли бы сделать вот так:

<bindings>
    <netMsmqBinding>
        <binding name="PosionMessageHandling"
             receiveRetryCount="3"
             retryCycleDelay="00:05:00"
             maxRetryCycles="3"
             receiveErrorHandling="Move" />
    </netMsmqBinding>
</bindings>

WCF сразу же повторит попытку получения ReceiveRetryCount после первого отказа вызова. После того, как пакет не прошел, сообщение перемещается в очередь повторов. После задержки минуты RetryCycleDelay сообщение переместилось из очереди повтора в очередь конечных точек, и партия была повторена. Это будет повторяться Время MaxRetryCycle. Если все это не удается, сообщение обрабатывается в соответствии с acceptErrorHandling, который может перемещаться (для отравления очереди), отклонения, падения или ошибки

Кстати, хороший текст о WCF и MSMQ - это глава 9 книги Progammig WCF от Juval Lowy

Ответ 3

Если вы используете SQL-Server, тогда вы должны использовать распределенную транзакцию, так как поддерживают ее как MSMQ, так и SQL-Server. Что происходит, вы завершаете запись базы данных в блок TransactionScope и вызываете scope.Complete() только в том случае, если это удается. Если это не удастся, тогда, когда ваш метод WCF вернет сообщение, он будет помещен обратно в очередь для повторной проверки. Здесь используется обрезанная версия кода, который я использую:

    [OperationBehavior(TransactionScopeRequired=true, TransactionAutoComplete=true)]
    public void InsertRecord(RecordType record)
    {
        try
        {
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
            {
                SqlConnection InsertConnection = new SqlConnection(ConnectionString);
                InsertConnection.Open();

                // Insert statements go here

                InsertConnection.Close();

                // Vote to commit the transaction if there were no failures
                scope.Complete();
            }
        }
        catch (Exception ex)
        {
            logger.WarnException(string.Format("Distributed transaction failure for {0}", 
                Transaction.Current.TransactionInformation.DistributedIdentifier.ToString()),
                ex);
        }
     }

Я тестирую это, ставя в очередь большое, но известное количество записей, позволяя WCF запускать много потоков для обработки многих из них одновременно (доходит до 16 потоков - 16 сообщений из очереди сразу), а затем убивает процесс в середина операций. Когда программа перезапускается, сообщения считываются из очереди и обрабатываются снова, как будто ничего не произошло, и по завершении теста база данных согласована и не имеет отсутствующих записей.

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

Ответ 4

К сожалению, я застрял в Windows XP и Windows Server 2003, так что это не вариант для меня. - (Я уточню, что в моем вопросе, когда я нашел это решение после публикации и понял, я не мог его использовать)

Я обнаружил, что одним из решений было настроить настраиваемый обработчик, который переместил бы мое сообщение в очередную очередь или ядовитую очередь и перезапустил мою службу. Мне это казалось безумным. Представьте, что мой сервер Sql не работает, как часто перезапуск службы.

. То, что я закончил, позволяет Линии ошибиться и оставить сообщения в очереди. Я также регистрирую фатальное сообщение в моей службе ведения журнала, что это произошло. После устранения проблемы я перезапускаю службу, и все сообщения начинают обрабатываться повторно.

Я понял, что повторная обработка этого сообщения или любая другая ошибка будет завершена, поэтому почему нужно переместить это сообщение, а остальные - в другую очередь. Я также могу остановить свое обслуживание и начать его снова, когда все работает как ожидалось.

aogan, у вас был идеальный ответ для MSMQ 4.0, но, к сожалению, не для меня