Я создал службу WCF и использую привязку netMsmqBinding.
Это простая служба, которая передает Dto моему методу службы и не ожидает ответа. Сообщение помещается в MSMQ и после получения вставляется в базу данных.
Как лучше всего убедиться, что данные не теряются?
Я пробовал 2 следующих метода:
Выбросить исключение
Это помещает сообщение в очередь недоставленных сообщений для просмотра вручную. Я могу обработать это, когда мой strvice запустится
установите для привязки значение receiveRetryCount = "3"
После 3 попыток, которые происходят мгновенно, сообщение, похоже, остается в очереди, но моя служба вызывает ошибку. При перезапуске службы этот процесс повторяется.
В идеале я бы хотел сделать следующее:
Попробуйте обработать сообщение
Могу ли я этого добиться? Если да, то как? Не могли бы вы указать мне на какие-нибудь хорошие статьи о том, как лучше всего использовать WCF и MSMQ для моих заданных сценариев.
Любая помощь приветствуется. Спасибо!
Некоторая дополнительная информация
Я использую MSMQ 3.0 в Windows XP и Windows Server 2003. К сожалению, я не могу использовать встроенную поддержку подозрительных сообщений, предназначенную для MSMQ 4.0 и Vista / 2008.





Я думаю, что с MSMQ (доступным только в Vista) вы могли бы сделать следующее:
<bindings>
<netMsmqBinding>
<binding name = "PosionMessageHandling"
receiveRetryCount = "3"
retryCycleDelay = "00:05:00"
maxRetryCycles = "3"
receiveErrorHandling = "Move" />
</netMsmqBinding>
</bindings>
WCF немедленно повторит попытку ReceiveRetryCount раз после сбоя первого вызова. После сбоя пакета сообщение перемещается в очередь повторных попыток. После задержки в минуту RetryCycleDelay сообщение перемещается из очереди повтора в очередь конечной точки, и пакет повторяется. Это будет повторяться Время MaxRetryCycle. Если все это не удается, сообщение обрабатывается в соответствии с receiveErrorHandling, который можно переместить. (чтобы отравить очередь), отклонить, отбросить или отказать
Кстати, хороший текст о WCF и MSMQ - это глава 9 книги Progammig WCF от Juval Lowy.
К сожалению, я застрял на Windows XP и Windows Server 2003, так что это не вариант для меня. - (Я уточню это в своем вопросе, поскольку нашел это решение после публикации и понял, что не могу его использовать)
Я обнаружил, что одним из решений было настроить собственный обработчик, который переместил бы мое сообщение в другую очередь или опасную очередь и перезапустил мою службу. Мне это казалось безумием. Представьте, что мой сервер Sql не работает, как часто служба будет перезапускаться.
Итак, в конечном итоге я позволил Line выйти из строя и оставить сообщения в очереди. Я также регистрирую фатальное сообщение в моей службе ведения системного журнала, что это произошло. Как только наша проблема решена, я перезапускаю службу, и все сообщения снова начинают обрабатываться.
Я понял, что повторная обработка этого или любого другого сообщения потерпит неудачу, поэтому зачем перемещать это сообщение и другие сообщения в другую очередь? С таким же успехом я могу остановить свою службу и запустить ее снова, когда все будет работать должным образом.
aogan, у вас был идеальный ответ для MSMQ 4.0, но, к сожалению, не для меня
Если вы используете 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, он автоматически ищет текущую транзакцию в рамках вызова метода, который должен был быть уже создан WCF, когда он вытащил сообщение из очереди. и вызвал ваш метод.
Привет, Крис. Я уверен, что приписывание вашего рабочего поведения TransactionScopeRequired = true отменяет необходимость заключать ваши Sql-вызовы в область транзакции, поскольку это уже делается. При этом я не уверен, как ваш ответ соотносится с моим вопросом о MSMQ.
В SDK есть образец, который может быть полезен в вашем случае. По сути, он присоединяет к вашей службе реализацию IErrorHandler, которая перехватывает ошибку, когда WCF объявляет сообщение «ядовитым» (т.е. когда все настроенные повторные попытки исчерпаны). Образец перемещает сообщение в другую очередь, а затем перезапускает ServiceHost, связанный с сообщением (поскольку при обнаружении опасного сообщения произойдет сбой).
Это не очень красивый образец, но он может быть полезен. Однако есть несколько ограничений:
1- Если у вас есть несколько конечных точек, связанных с вашей службой (т.е. выставленных через несколько очередей), нет способа узнать, в какую очередь прибыло опасное сообщение. Если у вас только одна очередь, это не будет проблемой. Я не видел официального обходного пути для этого, но я экспериментировал с одной возможной альтернативой, которую я задокументировал здесь: http://winterdom.com/weblog/2008/05/27/NetMSMQAndPoisonMessages.aspx
2- Как только сообщение о проблеме перемещается в другую очередь, это становится вашей ответственностью, поэтому вы должны переместить его обратно в очередь обработки после истечения тайм-аута (или присоединить новую службу к этой очереди для ее обработки).
Честно говоря, в любом случае вы смотрите здесь на некоторую «ручную» работу, которую WCF просто не покрывает сама по себе.
Недавно я работал над другим проектом, в котором у меня есть требование явно контролировать частоту повторных попыток, и мое текущее решение заключалось в создании набора очередей повторных попыток и ручном перемещении сообщений между очередями повторных попыток и основной очередью обработки на основе набор таймеров и некоторые эвристики, просто используя необработанный материал System.Messaging для обработки очередей MSMQ. Кажется, это работает довольно хорошо, хотя есть пара подводных камней, если вы пойдете этим путем.
Это относится к MSMQ 4.0, а не к MSMQ 3.0.