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

时间:2017-03-25 16:29:56

标签: java spring-boot rabbitmq spring-amqp spring-rabbitmq

我确实读过这个参考文献: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。

1 个答案:

答案 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