Как обрабатывать сбой сообщений в привязках 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.
Ответы
Ответ 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, но, к сожалению, не для меня