Java rabbitmq和spring rabbitmq中的DLX-拒绝消息的一些注意事项
我确实读过这篇参考文献:,但它并没有解决我的疑问,即:Java rabbitmq和spring rabbitmq中的DLX-拒绝消息的一些注意事项,java,spring-boot,rabbitmq,spring-amqp,spring-rabbit,Java,Spring Boot,Rabbitmq,Spring Amqp,Spring Rabbit,我确实读过这篇参考文献:,但它并没有解决我的疑问,即: 在接受消息的情况下没有问题-spring rabbitmqsend ack,一切正常,DLX不知道已确认的消息 问题在于拒绝回答的情况,即抛出MessageConverterException?此消息将被删除或移动到DLX 万一有其他例外呢?例如异常?它被删除/重新查询/移动到DLX 在@Gary回答后编辑 我认为,在回答@Gary之后,我应该添加更多关于我的案例的细节和@Gary回答的一些总结@Gary完全掌握了我的用例 我不喜欢requ
在接受消息的情况下没有问题-
spring rabbitmq
send ack,一切正常,DLX
不知道已确认的消息
问题在于拒绝回答的情况,即抛出MessageConverterException
?此消息将被删除或移动到DLX
万一有其他例外呢?例如异常
?它被删除/重新查询/移动到DLX
在@Gary回答后编辑我认为,在回答@Gary之后,我应该添加更多关于我的案例的细节和@Gary回答的一些总结@Gary完全掌握了我的用例 我不喜欢requeue-从不(我害怕循环),但我不喜欢在抛出异常时丢失消息(例如与数据库的连接丢失)-此消息应重新发送到
DLX
。另一方面,消息转换应被视为致命错误-无需重新请求,无需重新发送到DLX-只是永久删除消息通常情况下,in取决于异常拒绝(=重新发送到DLX,如果已配置)或接受,从不重新请求。
简而言之,@Gary提出的方法。首先:我们可以覆盖
异常处理程序
来管理发送nack/ack的操作,这给了我们完全的控制权。第二个:在我看来更简单,解决方案是设置
defaultRequeueRejected=false
并在转换器中抛出ImmediateAcknowledgeAmqpException
。它使RabbitMQ
认为答案被接受(与第一个解决方案的情况相同),而且监听器不会被调用<代码>
**结论**:使用ImmediateAcknowledgeAmqpException
或
ExceptionHandler`exception,我们可以完全控制永久拒绝消息(在hood ack下)和重新发送到DLX RabbitMQ对异常一无所知
当容器捕获到异常时,它调用channel.basicRequest(deliveryTag,requeue)
如果requeue为true,则消息将被重新查询
默认情况下,除上述情况外的任何例外情况
o、 s.amqp…MessageConversionException
o、 s.messaging…MessageConversionException
o、 美国消息传递…MethodArgumentNotValidException
o、 美国消息传递…MethodArgumentTypeMismatchException
java.lang.NoSuchMethodException
java.lang.ClassCastException
requeue
设置为true,因此消息将被重新查询
对于这些例外情况,传递被认为是致命的,并且消息不会被重新请求,如果配置了DLX/DLQ,它将转到DLX/DLQ
容器有一个默认为true的标志defaultRequeueRejected
;如果将其设置为false
;不会重新查询任何例外情况
对于应用程序级异常,通常会重新查询消息。要动态拒绝(而不是重新排队)消息,请确保原因链中存在AmqpRejectAndDontRequeueException
。这指示容器不要重新获取消息,它将转到DLX/DLQ(如果已配置)。此行为由上面提到的defaultRequeueRejected
标志启用
这些都在文档中进行了解释,正如我在其他回答中所讨论的,您可以通过使用自定义错误处理程序来更改此行为;文档中也解释了这一点
无法向DLX/DLQ发送某些异常,而不能发送其他异常;rabbit只有一个二进制选项requeue或don't requeue,对于后者,如果配置了DLX/DLQ,则所有这些被拒绝的消息都会转到DLX/DLQ
Spring AMQP提供了另外一个异常,ImmediateAcknowledgeAmqpException
。如果您的侦听器引发此异常,则消息将被确认为已成功处理(channel.basicAck()
)。这是容器提供的唯一技术,即丢弃错误消息而不将其发送到DLX/DLQ
当然,您的应用程序本身也可以删除这些消息
如果要DLX/DLQ所有业务异常,但要删除转换异常,请从转换器中抛出
amqprejected和dontrequeueexception
(或将defaultRequeueRejected
设置为false),并立即抛出KnowledgeAmqpeption
。谢谢您的明确回答。我编辑我的帖子是为了澄清这个问题并总结你们的想法。什么方法(ExceptionHandler
或ImmediateAcknowledgeAmqpException
应该使用?IMOImmediateAcknowledgeAmqpException
,因为它更简单,并提供完全控制。这是您的选择;对于自定义转换器,在那里执行此操作可能更容易/更简单,并使用标准错误处理程序。如果您希望使用其他converters也一样,并且想要相同的行为,自定义错误处理程序可能更好。但您在编辑中的分析是正确的。当涉及到ErrorHandler
-应该覆盖哪些函数(请记住DLX已配置)?我认为isFatal
在这方面会有所帮助。我们应该设置defaultRequeueRejected=false
来整体阻止重新查询。然后,从isFatal
返回true,我们确保消息不会被重新发送到DLX
,只需永久删除。当我们从isFatal
false返回时,它将自动被删除esend toDLX
。是吗?我建议您使用自定义的ErrorHandler
,而不是试图使ConditionalRejectingErrorHandler
满足您的需要-它仅用于分析异常以确定是否应重新查询消息。您需要其他功能-决定是否使用异常后的消息,或者不是。一个简单的错误