Как сделать обработку ошибок с помощью EasyNetQ / RabbitMQ
Я использую RabbitMQ в C# с библиотекой EasyNetQ. Я использую шаблон pub / sub здесь. У меня все еще есть несколько вопросов, которые, я надеюсь, кто-нибудь может мне помочь:
- когда есть ошибка при потреблении сообщения, оно автоматически перемещается в очередь ошибок. Как я могу реализовать повторные попытки (чтобы он был помещен обратно в исходную очередь, и когда он не обрабатывает X раз, он перемещается в очередь мертвых букв)?
- насколько я вижу, всегда есть 1 очередь ошибок это используется для сброса сообщений из всех других очередей. Как я могу иметь 1 очередь ошибок для каждого типа, чтобы каждая очередь имела свою собственную связанную очередь ошибок?
- как я могу легко повторить сообщения, которые находятся в очереди ошибок? Я попробовал Hosepipe, но он просто переиздает сообщения в очередь ошибок вместо исходной очереди. Мне тоже не нравится этот вариант, потому что я не хочу возиться с консолью. Предпочтительно, я бы просто запрограммировал против ошибки очередь.
кого?
2 ответов
проблема, с которой вы сталкиваетесь с EasyNetQ/RabbitMQ, заключается в том, что она намного более "сырая" по сравнению с другими службами обмена сообщениями, такими как SQS или Azure Service Bus / Queues, но я сделаю все возможное, чтобы указать вам в правильном направлении.
Вопрос 1.
Это будет на вас. Самый простой способ заключается в том, что вы не можете-Ack сообщение в RabbitMQ/EasyNetQ, и он будет помещен во главе очереди для вас, чтобы повторить попытку. Это не реально желательно, потому что он будет повторен почти сразу (без временной задержки), а также заблокирует другие сообщения от обработки (Если у вас есть один подписчик с количеством предварительной выборки 1).
Я видел другие реализации использования "MessageEnvelope". Таким образом, класс-оболочка, который при сбое сообщения увеличивает переменную retry в MessageEnvelope и повторно передает сообщение обратно в очередь. Вам нужно будет сделать это и написать код упаковки вокруг Вашего сообщения обработчики, это не будет функцией EasyNetQ.
используя вышеизложенное, я также видел, как люди используют конверты, но позволяют сообщению быть мертвыми буквами. После того, как он находится в очереди мертвых писем, есть другое приложение/рабочий чтение элементов из очереди мертвых писем.
все эти подходы выше имеют небольшую проблему в том, что на самом деле нет никакого хорошего способа иметь логарифмическую/экспоненциальную/любую увеличивающуюся задержку в обработке сообщения. Вы можете "держать" сообщение в коде в течение некоторого времени, прежде чем вернуть его в очередь, но это не очень хороший способ.
из всех этих опций ваше собственное пользовательское приложение читает очередь мертвых писем и решает, перенаправлять ли сообщение на основе конверта, содержащего счетчик повторных попыток, вероятно, лучший способ.
Вопрос 2.
вы можете указать обмен мертвыми письмами в очереди с помощью расширенного API. (https://github.com/EasyNetQ/EasyNetQ/wiki/The-Advanced-API#declaring-queues). Однако это означает, что вам придется использовать расширенный API практически везде, поскольку использование простой реализации IBus subscribe/publish ищет очереди, которые называются на основе типа сообщения и имени подписчика. Использование пользовательского объявления очереди означает, что вы будете обрабатывать имена своих очередей самостоятельно, что означает, что при подписке вам нужно будет знать имя того, что вы хотите и т. д. Нет больше авто подписки для вас!
Вопрос 3
очередь ошибок / очередь мертвых писем - это просто еще одна очередь. Вы можете слушать эту очередь и делать с ней то, что вам нужно. Но на самом деле нет никакого решения из коробки, которое звучит так, как будто оно соответствует вашим потребностям.
я реализовал именно то, что вы описали. Вот несколько советов, основанных на моем опыте и связанных с каждым из ваших вопросов.
Q1 (как повторить x раз):
для этого вы можете использовать IMessage.Body.BasicProperties.Headers
. Когда вы потребляете сообщение из очереди ошибок, просто добавьте заголовок с выбранным именем. Найдите этот заголовок в каждом сообщении, которое входит в очередь ошибок, и увеличьте его. Это даст вам подсчет повторных попыток.
это очень важно что у вас есть стратегия для того, что делать, когда сообщение превышает предел повтора X. Вы не хотите потерять это сообщение. В моем случае, я пишу сообщение на диск в этот момент. Это дает вам много полезной отладочной информации, чтобы вернуться позже, потому что EasyNetQ автоматически обертывает исходное сообщение с информацией об ошибке. Он также имеет исходное сообщение, чтобы вы могли, если хотите, вручную (или, возможно, автоматически, через какой-то пакетный код повторной обработки) запросите сообщение позже каким-то контролируемым способом.
вы можете посмотреть код в утилите шланга, чтобы увидеть хороший способ сделать это. Фактически, если вы следуете шаблону, который вы видите там, то вы даже можете использовать шланг позже, чтобы запросить сообщения, если вам нужно.
Q2 (как создать очередь ошибок на исходную очередь):
вы можете использовать автобус Easynetq Advanced, чтобы сделать это чисто. Использовать IBus.Advanced.Container.Resolve<IConventions>
чтобы добраться до интерфейса конвенций. Затем вы можете установить соглашения для именования очереди ошибок с помощью conventions.ErrorExchangeNamingConvention
и conventions.ErrorQueueNamingConvention
. В моем случае я устанавливаю соглашение на основе имени исходной очереди, чтобы получить пару очередей queue_error каждый раз, когда я создаю очередь.
Q3 (как обрабатывать сообщения в очередях ошибок):
вы можете объявить потребителя для очереди ошибок так же, как и для любой другой очереди. Опять же, AdvancedBus позволяет сделать это чисто, указав, что тип выхода из очереди -EasyNetQ.SystemMessage.Error
. Итак,IAdvancedBus.Consume<EasyNetQ.SystemMessage.Error>()
доставит вас туда. Повторная попытка просто означает повторную публикацию в исходном exchange (обращая внимание на счетчик повторных попыток, который вы помещаете в заголовок (см. Мой ответ на Q1 выше), и информация в сообщении об ошибке, которую вы потребляли из очереди ошибок, может помочь вам найти цель для повторной публикации.