rabbitmq 和 spring-rabbitmq 中的 DLX - 拒绝消息的一些注意事项



我确实读过这个参考: https://www.rabbitmq.com/dlx.html,但它并没有解决我的疑问,即:
在接受消息的情况下没有问题 -spring-rabbitmq发送 ack 并且一切都很好,DLX不知道 acked 消息。

问题是在拒绝答案的情况下,即扔MessageConverterException呢? 此消息已删除或移至DLX

万一其他例外呢?例如Exception? 它被删除/重新排队/移动到DLX

在回答@Gary
后编辑 我认为,在回答@Gary之后,我应该添加有关我的案例的更多详细信息以及@Gary答案的一些摘要。 @Gary完全掌握了我的用例。

我不想重新排队 - 从不(我害怕循环),但我不想在抛出异常时丢失消息(例如失去与数据库的连接) - 此消息应重新发送到DLX。另一方面,消息转换应被视为致命错误 - 没有重新排队,没有重新发送到DLX - 只是永久删除消息。通常,取决于异常,要么拒绝(=重新发送到DLX,如果已配置)要么接受,从不重新排队。

简而言之,@Gary提出的方法。
首先:我们可以覆盖ExceptionHandler来管理发送 nack/ack,这给了我们完全的控制权。
第二:IMO更简单,解决方案是设置defaultRequeueRejected=false并在转换器中抛出ImmediateAcknowledgeAmqpException。它使RabbitMQ认为答案被接受(与第一个解决方案的情况相同),而且不会调用侦听器。 **Conclusion**: UsingImmediateAcknowledgeAmqpExceptionorExceptionHandler' Exception,我们可以完全控制永久拒绝消息(在引擎盖下)并重新发送到DLX。

RabbitMQ 对这些异常一无所知。

当容器捕获异常时,它会调用channel.basicReject(deliveryTag, requeue)

如果重新排队为 true,则邮件将重新排队。

默认情况下,对于此处提到的例外以外的任何例外

o.s.amqp...消息转换异常

o.s.消息传递...消息转换异常

o.s.消息传递...MethodArgumentNotValidException

o.s.消息传递...方法参数类型不匹配异常

java.lang.NoSuchMethodException

java.lang.ClassCastException

requeue设置为 true,因此消息将重新排队。

对于这些例外,传递被认为是致命的,并且消息不会重新排队,如果配置了DLX/DLQ,它将转到DLX/DLQ。

容器有一个标志defaultRequeueRejected默认情况下为 true;如果将其设置为false;则不会重新排队。

对于应用程序级异常,通常,消息将重新排队。若要动态拒绝(而不是重新排队)消息,请确保原因链中存在AmqpRejectAndDontRequeueException。这将指示容器不要对消息重新排队,它将转到 DLX/DLQ(如果已配置)。此行为由上面提到的defaultRequeueRejected标志启用。

这在文档中都有解释,正如我在其他回答中讨论的那样,您可以使用自定义错误处理程序来更改此行为;文档中也对此进行了解释。

不可能向DLX/DLQ发送一些例外,而不能发送其他例外;Rabbit只有一个二进制选项,重新排队或不重新排队,对于后者,如果配置了DLX/DLQ,则所有此类拒绝的消息都将转到DLX/DLQ。

Spring AMQP 提供了另一个例外,ImmediateAcknowledgeAmqpException。如果侦听器抛出此异常,则消息将被确认为已成功处理(channel.basicAck())。这是容器提供的唯一技术,可以丢弃错误消息而不将其发送到DLX/DLQ。

当然,您的应用程序本身可以删除此类消息。

如果要 DLX/DLQ 所有业务例外,但删除转换例外,请抛出AmqpRejectAndDontRequeueException(或将defaultRequeueRejected设置为 false),然后从转换器中抛出ImmediateAcknowledgeAmqpException

最新更新