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

DLX in rabbitmq and spring-rabbitmq - some considerations of rejecting messages

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

问题是万一拒绝回答,即抛出 MessageConverterException 怎么办?此消息已删除或移至 DLX

如果出现其他异常怎么办?例如 Exception ?是 removed/requeued/moved 到 DLX 吗?

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

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

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

RabbitMQ 对异常一无所知。

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

如果 requeue 为 true,则消息被重新排队。

默认情况下,对于未提及的任何异常 here

o.s.amqp...MessageConversionException

o.s.messaging...MessageConversionException

o.s.messaging...MethodArgumentNotValidException

o.s.messaging...MethodArgumentTypeMismatchException

java.lang.NoSuchMethodException

java.lang.ClassCastException

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

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

容器有一个标志defaultRequeueRejected,默认为真;如果将其设置为 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 .