2008-09-17 2 views
17

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

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

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

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

  1. Бросьте исключение

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

  2. схватываться receiveRetryCount = «3» на связывающие

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

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

процесс Try сообщение

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

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

Любая помощь будет высоко оценена. Благодаря!

Некоторая дополнительная информация

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

ответ

9

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

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

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

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

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

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

14

Я думаю, что с MSMQ (Avaiable только на 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 является chapther 9 из Progammig WCF книги из Juval Lowy

+0

Это относится к MSMQ 4.0, а не MSMQ 3.0 – Perhentian 2011-11-16 12:34:19

1

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

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

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

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

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

4

Если вы используете SQL-сервер, то вы должны использовать распределенную транзакцию, так как MSMQ и поддержка SQL-сервера его. Что происходит, вы завершаете запись базы данных в блок 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, когда она выскочила сообщение из очереди и вызывается ваш метод.

+0

Hi Chris. Я уверен, что приписывая поведение вашей операции TransactionScopeRequired = true, отрицает необходимость переноса ваших вызовов Sql в область транзакций, поскольку это уже выполняется. Это, как говорится, я не уверен, как ваш ответ относится к моему вопросу о MSMQ. – WebDude 2008-09-17 13:23:30

Смежные вопросы