我正在使用RabbitMQ,我有一个包含电子邮件的队列。我的消费者服务将消息排队并尝试发送消息。如果由于任何原因,我的消费者无法发送消息,我想重新排队消息再次发送。我意识到我可以做一个basicNack并将重新排队标志设置为true,但是,我不想无限期地重新排列该消息(例如,如果我们的电子邮件系统出现故障,我不想连续重新排队未发送的消息)。我想定义有限次数,我可以重新排列要再次发送的消息。但是,当我将它出列并发送一个nack时,我无法在电子邮件消息对象上设置字段。更新的字段不存在于队列中的消息上。还有其他方法可以解决这个问题吗?提前谢谢。
答案 0 :(得分:57)
在RabbitMQ(以及AMQP协议)中没有像重试尝试这样的功能。
实现重试尝试的可能解决方案限制行为:
如果以前没有重新传递Redeliver消息(检查redelivered
方法上的basic.deliver
参数 - 您的库应该有一些接口)并删除它然后捕获{{3}然后以某种方式处理。
每次无法处理消息时再次发布,但设置或增加/减少标题字段,比如x-redelivered-count
(您可以选择任何您喜欢的名称)。要在这种情况下控制重新传输,您必须检查您设置的字段是否达到某个限制(顶部或底部 - 0是我的选择,来自tcp / ip的ip标头中的a-la ttl
。
在Redis,memcache或其他存储中存储消息唯一键(比如uuid,但你必须手动设置它),即使在mysql旁边还有重新计数,然后在每次重新传递增量/减量时价值直到达到极限。
(对于真正的极客)编写将实现此类行为的插件。
#3 的专业人员是重新传递的消息留在队列头部。如果你有很长的队列或者消息顺序对你很重要,那么这很重要(注意,重新发送会破坏严格的消息顺序,详见官方文档或dead letter exchange)。
P.S。:
本主题中有this question on SO,但在php中。仔细看看,也许它会对你有所帮助(从&#34开始阅读;有多种技术可以解决循环再生问题" 。
答案 1 :(得分:0)
尽管这是一个老问题,我认为您现在可以通过将死信交换和消息死信后添加的x-death标头数组结合起来轻松地做到这一点:
死信过程将数组添加到每个名为x-death的死信消息的标头中。该数组包含每个死字符事件的条目,由一对{queue,reason}标识。每个这样的条目都是一个包含几个字段的表:
queue:消息之前所在的队列的名称 固定字母
原因:刻字失效的原因,见下文
time:消息失效的日期和时间,以64位AMQP 0-9-1时间戳为字母
exchange-消息发布到的交换(请注意,如果消息是不带字母的,这将是一个不带字母的交换 多次)
路由键:发布消息的路由键(包括CC密钥,但不包括BCC密钥)
计数:由于这个原因该消息在该队列中被死信了多少次
原始过期时间(如果邮件由于每个邮件的TTL而被废弃):邮件的原始过期属性。的 过期属性已从邮件中的死信中删除 为了防止它在路由到的任何队列中再次过期。
PS:您也可以使用投放标签字段
阅读此great article以获得更多信息
检查本次抽奖:
答案 2 :(得分:0)
从我的角度来看,这里更好的主意是在使用者内部实现死信交换和重试逻辑的组合。如果使用者无法处理消息,则可以将消息放入DeadLetterQueue
下面,您可以找到通过node-amqp和Rabbitmq https://github.com/kharandziuk/dead-letter-exchange-prototype实现的死信交换原型。