.net 如何在 RabbitMQ 中设置重试次数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/23158310/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 12:43:21  来源:igfitidea点击:

How do I set a number of retry attempts in RabbitMQ?

.netqueuerabbitmqconsumer

提问by user2689570

I am using RabbitMQ and I have a queue that holds email messages. My consumer service de-queues messages and attempts to send them. If, for any reason, my consumer cannot send the message, I would like to re-queue the message to send again. I realize I can do a basicNack and set the requeue flag to be true, however, I don't want to requeue the message indefinitely (say, if our email system goes down, I don't want to continuously requeue unsent messages). I would like to define a finite number of times that I can requeue the message to be sent again. I can't set a field on the email message object, however, when I dequeue it and send a nack. The updated field is not present on the message in the queue. Is there any other way in which I can approach this? Thanks in advance.

我正在使用 RabbitMQ 并且我有一个保存电子邮件的队列。我的消费者服务使消息出队并尝试发送它们。如果由于任何原因我的消费者无法发送消息,我想重新排队消息以再次发送。我意识到我可以做一个 basicNack 并将重新排队标志设置为 true,但是,我不想无限期地重新排队邮件(例如,如果我们的电子邮件系统出现故障,我不想连续重新排队未发送的邮件)。我想定义一个有限的次数,我可以将要再次发送的消息重新排队。但是,当我将其出列并发送 nack 时,我无法在电子邮件消息对象上设置字段。队列中的消息上不存在更新的字段。有没有其他方法可以解决这个问题?提前致谢。

回答by pinepain

There are no such feature like retry attempts in RabbitMQ (as well as in AMQP protocol).

在 RabbitMQ(以及 AMQP 协议)中没有像重试这样的功能。

Possible solution to implement retry attempts limit behavior:

实现重试尝试限制行为的可能解决方案:

  1. Redeliver message if it was not previously redelivered (check redeliveredparameter on basic.delivermethod - your library should have some interface for this) and drop it and then catch in dead letter exchange, then process somehow.

  2. Each time message cannot be processed publish it again but set or increment/decrement header field, say x-redelivered-count(you can chose any name you like, though). To get control over redeliveries in this case you have to check the field you set whether it reaches some limit (top or bottom - 0 is my choise, a-la ttlin ip header from tcp/ip).

  3. Store message unique key (say uuid, but you have to set it manually when you publish message) in Redis, memcache or other storage, even in mysql alongside with redeliveries count and then on each redelivery increment/decrement this value until it reach the limit.

  4. (for real geeks) write plugin that will implement such behavior like you want.

  1. 如果之前没有重新传递消息,则重新传递消息(检查方法上的redelivered参数basic.deliver- 您的库应该有一些接口)并删除它,然后在死信交换中捕获,然后以某种方式进行处理。

  2. 每次无法处理消息时,再次发布它,但设置或增加/减少头字段,例如x-redelivered-count(不过,您可以选择任何您喜欢的名称)。在这种情况下,要控制重新交付,您必须检查您设置的字段是否达到某个限制(顶部或底部 - 0 是我的选择,a-lattl在来自 tcp/ip 的 ip 标头中)。

  3. 将消息唯一键(比如 uuid,但您在发布消息时必须手动设置)存储在 Redis、memcache 或其他存储中,甚至在 mysql 中与重新交付计数一起存储,然后在每次重新交付时增加/减少该值,直到达到限制.

  4. (对于真正的极客)编写插件来实现你想要的这种行为。

The pro of #3is that redelivered message stay in queue head. This is important if you have long queue or if message order is important for you (note, that redeliveries will break strict messages order, see official docs for details or this question on SO).

#3是重新传递消息留在队列头。如果您有很长的队列或者消息顺序对您很重要,这很重要(请注意,重新传递会破坏严格的消息顺序,有关详细信息,请参阅官方文档或有关 SO 的此问题)。

P.S.:

PS:

There is similar answerin this topic, but in php. Look through it, maybe it helps you a bit (start reading it from words "There are multiple techniques to deal with cycle redeliver problem".

本主题中有类似的答案,但在 php.ini 中。仔细阅读它,也许它对您有所帮助(从“有多种技术可以处理循环重新交付问题”开始阅读它。

回答by Mohammed Essehemy

Although this is an old question I think you can now easily do this with the combination of dead letter exchanges and x-deathheader array added once a message is dead lettered:

虽然这是一个老问题,但我认为您现在可以通过死信交换和x-death标题数组的组合轻松地做到这一点,一旦消息被死信:

The dead-lettering process adds an array to the header of each dead-lettered message named x-death. This array contains an entry for each dead lettering event, identified by a pair of {queue, reason}. Each such entry is a table that consists of several fields:

queue: the name of the queue the message was in before it was dead-lettered

reason: reason for dead lettering, see below

time: the date and time the message was dead lettered as a 64-bit AMQP 0-9-1 timestamp

exchange - the exchange the message was published to (note that this will be a dead letter exchange if the message is dead lettered multiple times)

routing-keys: the routing keys (including CC keys but excluding BCC ones) the message was published with

count: how many times this message was dead-lettered in this queue for this reason

original-expiration (if the message was dead-letterered due to per-message TTL): the original expiration property of the message. The expiration property is removed from the message on dead-lettering in order to prevent it from expiring again in any queues it is routed to.

死信过程将一个数组添加到每个名为 x-death 的死信消息的标题中。此数组包含每个死字事件的条目,由一对 {queue, reason} 标识。每个这样的条目都是一个由几个字段组成的表:

queue:消息在死信之前所在队列的名称

原因:死字的原因,见下文

时间:消息被死信的日期和时间,为 64 位 AMQP 0-9-1 时间戳

交换 - 消息发布到的交换(请注意,如果消息多次死信,这将是死信交换)

路由密钥:消息发布时使用的路由密钥(包括 CC 密钥,但不包括 BCC 密钥)

计数:由于这个原因,这条消息在这个队列中被死信多少次

original-expiration(如果消息由于每条消息的 TTL 是死信的):消息的原始到期属性。过期属性会从死信消息中删除,以防止它在路由到的任何队列中再次过期。

Read this great articlefor more info

阅读这篇很棒的文章了解更多信息

check this draw:

检查这个抽奖:

enter image description here

在此处输入图片说明

回答by kharandziuk

From my perspective the better idea here is to implement a combination of dead-letter exchange and retry logic inside of the consumer. If the consumer fails to handle the message then you put a message into a DeadLetterQueue

从我的角度来看,这里更好的想法是在消费者内部实现死信交换和重试逻辑的组合。如果消费者无法处理该消息,则将消息放入 DeadLetterQueue

Bellow you can find a prototype of dead-letter-exchange implemented with node-amqp and Rabbitmq https://github.com/kharandziuk/dead-letter-exchange-prototype.

下面你可以找到一个用 node-amqp 和 Rabbitmq https://github.com/kharandziuk/dead-letter-exchange-prototype实现的死信交换原型。