Dead-lettering dead-lettered RabbitMQ 中的消息
Dead-lettering dead-lettered messages in RabbitMQ
我们这里有:
- 主题交流
DLE
,旨在成为 Dead-Letter 交流
- 主题交流
E
,即"main"交流
- 几个 Queues (
EQ1
, ..., EQn
) 绑定到 E
(并用 x-dead-letter-exchange = DLE
初始化),每个都有自己的路由钥匙。这些 queue 是被消耗的。
- 对于每个
EQn
,有一个 DLEQn
(用 x-dead-letter-exchange = E
和 x-message-ttl = 5000
初始化),绑定到 DLE
,使用与 EQn
。这些 queue 是 而不是 从 消耗的
我想要的是以下内容:如果消费者无法处理来自 EQn
的消息,它会使用 requeue: false
拒绝消息并到达 DLEQn
- 也就是说,到 Dead-Letter 交易所的适当 queue。现在,我希望此消息在 DLEQn
上停留一段时间,然后路由回原始 queue EQn
以再次处理。
尽我所能,我无法让 "redelivery to the original queue" 工作。我看到消息位于 DLEQn
中,所有正确的 headers 和路由密钥都完好无损,但在 TTL 到期后它们就消失得无影无踪。
我做错了什么?
RabbitMQ 检测消息流循环(E -> DLE -> E -> DLE ...)并静默丢弃消息:
来自DLX manual (Routing Dead-Lettered Messages section):
It is possible to form a cycle of dead-letter queues. For instance, this can happen when a queue dead-letters messages to the default exchange without specifiying a dead-letter routing key. Messages in such cycles (i.e. messages that reach the same queue twice) will be dropped if the entire cycle is due to message expiry.
是的,你可以做到。我们目前正在生产中这样做,效果很好。代码太长,无法包含在此处,但我将向您展示我创建的表示流程的图表。基本思想是第一个 DLX 有一个 TTL,一旦 TTL 到期,消息就会进入第二个队列,重新发送回原始队列。
那个 post 已经很老了,但我花了几天时间才找到类似问题的解决方案,所以我想我应该在这里分享我的解决方案。
我们正在 TargetQueue 中接收消息(没有 TTL!!!,绑定到 TargetExchange),这可能会被消费者拒绝。 TargetQueue定义了一个DLX(RetryExchange),它又绑定了一个相应的队列(RetryQueue,TTL为60秒,TargetExchange定义为DLX)。
因此,如果消费者 nacks 来自 TargetQueue 的消息,它会在 RetryQueue 中排队,并且由于 TTL,消息会再次 nacked 并在原始 TargetQueue 中重新排队。线索是,TargetQueue 可能没有定义 TTL,否则 RabbitMQ 日志中会出现这样的消息:
Dead-letter queues cycle detected: [<<"TargetQueue">>,<<"RetryQueue">>,<<"TargetQueue">>]
所以最终解决方案非常简单(并且只需要一个消费者)。最后的灵感来自https://medium.com/@igkuz/ruby-retry-scheduled-tasks-with-dead-letter-exchange-in-rabbitmq-9e38aa39089b
我们这里有:
- 主题交流
DLE
,旨在成为 Dead-Letter 交流 - 主题交流
E
,即"main"交流 - 几个 Queues (
EQ1
, ...,EQn
) 绑定到E
(并用x-dead-letter-exchange = DLE
初始化),每个都有自己的路由钥匙。这些 queue 是被消耗的。 - 对于每个
EQn
,有一个DLEQn
(用x-dead-letter-exchange = E
和x-message-ttl = 5000
初始化),绑定到DLE
,使用与EQn
。这些 queue 是 而不是 从 消耗的
我想要的是以下内容:如果消费者无法处理来自 EQn
的消息,它会使用 requeue: false
拒绝消息并到达 DLEQn
- 也就是说,到 Dead-Letter 交易所的适当 queue。现在,我希望此消息在 DLEQn
上停留一段时间,然后路由回原始 queue EQn
以再次处理。
尽我所能,我无法让 "redelivery to the original queue" 工作。我看到消息位于 DLEQn
中,所有正确的 headers 和路由密钥都完好无损,但在 TTL 到期后它们就消失得无影无踪。
我做错了什么?
RabbitMQ 检测消息流循环(E -> DLE -> E -> DLE ...)并静默丢弃消息:
来自DLX manual (Routing Dead-Lettered Messages section):
It is possible to form a cycle of dead-letter queues. For instance, this can happen when a queue dead-letters messages to the default exchange without specifiying a dead-letter routing key. Messages in such cycles (i.e. messages that reach the same queue twice) will be dropped if the entire cycle is due to message expiry.
是的,你可以做到。我们目前正在生产中这样做,效果很好。代码太长,无法包含在此处,但我将向您展示我创建的表示流程的图表。基本思想是第一个 DLX 有一个 TTL,一旦 TTL 到期,消息就会进入第二个队列,重新发送回原始队列。
那个 post 已经很老了,但我花了几天时间才找到类似问题的解决方案,所以我想我应该在这里分享我的解决方案。
我们正在 TargetQueue 中接收消息(没有 TTL!!!,绑定到 TargetExchange),这可能会被消费者拒绝。 TargetQueue定义了一个DLX(RetryExchange),它又绑定了一个相应的队列(RetryQueue,TTL为60秒,TargetExchange定义为DLX)。
因此,如果消费者 nacks 来自 TargetQueue 的消息,它会在 RetryQueue 中排队,并且由于 TTL,消息会再次 nacked 并在原始 TargetQueue 中重新排队。线索是,TargetQueue 可能没有定义 TTL,否则 RabbitMQ 日志中会出现这样的消息:
Dead-letter queues cycle detected: [<<"TargetQueue">>,<<"RetryQueue">>,<<"TargetQueue">>]
所以最终解决方案非常简单(并且只需要一个消费者)。最后的灵感来自https://medium.com/@igkuz/ruby-retry-scheduled-tasks-with-dead-letter-exchange-in-rabbitmq-9e38aa39089b