我确实读过这个参考文献:https://www.rabbitmq.com/dlx.html,但它并没有解决我的疑虑,即:
在接受消息的情况下没有问题 - spring-rabbitmq
发送确认和外包很好,DLX
不知道有关已确认的消息。
问题在于拒绝回答,即投掷MessageConverterException
怎么办?此邮件已移除或移至DLX
?
如果是其他例外怎么办?例如Exception
?它被移除/重新排队/移至DLX
?
@Gary 回答后编辑 我想,在回答@Gary之后,我应该添加更多关于我的案例的细节以及@Gary的回答的一些总结。 @Gary正好抓住了我的用例。
我不想重新排队 - 从不(我害怕循环),但我不想在抛出异常时丢失消息(例如丢失与数据库的连接) - 此消息应该是重新发送到DLX
。另一方面,消息的转换应该被视为致命错误 - 没有重新排队,没有重新发送到DLX - 只是永久删除消息。 通常,取决于异常要么拒绝(=重新发送到DLX,如果已配置)或接受,请永远不要重新排队。
总结一下@Gary提出的简单方法
首先:我们可以覆盖ExceptionHandler
来管理发送nack / ack,这样就可以给我们一个完整的控制权。
第二:IMO更简单,解决方案是设置defaultRequeueRejected=false
并在转换器中抛出ImmediateAcknowledgeAmqpException
。它使RabbitMQ
认为答案被接受(与第一个解决方案相同),而且不会调用听众。
**Conclusion**: Using
ImmediateAcknowledgeAmqpException or
ExceptionHandler`例外我们对永久拒绝消息(在引擎盖下)完全控制并重新发送到DLX。
答案 0 :(得分:0)
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,它将转到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
。