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

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

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

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

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

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

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

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

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

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

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

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

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

Любая помощь приветствуется. Спасибо!

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
17
0
14 045
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Я думаю, что с 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.

Это относится к MSMQ 4.0, а не к MSMQ 3.0.

Perhentian 16.11.2011 16:34

К сожалению, я застрял на 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.

WebDude 17.09.2008 17:23
Ответ принят как подходящий

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

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

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

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

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

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

Другие вопросы по теме