问题
I did read this reference: https://www.rabbitmq.com/dlx.html, however it doesn't resolve my doubts, namely:
In case of accepting message there is no problem - spring-rabbitmq
send ack and everthing is fine, DLX
doesn't know about acked message.
The problem is in case rejecting answer, namely what about throwing MessageConverterException
? This message is removed or moved to DLX
?
And what about in case other exception ? For example Exception
? It is removed/requeued/moved to DLX
?
Edit after answer of @Gary
I think, that after answer's @Gary I should add more details about my case and some summary of @Gary's answer. @Gary exactly grasped my use case.
I wouldn't like requeue - never (I am afraid of looping), but I wouldn't like to lose messages when an exception was thrown (for example lost connection to database) - this message should be resend to DLX
. On the other hand, conversion of message should be treated as fatal error - no requeue, no resend to DLX - simply permanent removing message. Generally, in depends on exception either reject (=resend to DLX if configured) or accept, never requeue.
To sum up in a nutshell approach proposed by @Gary.
First: We can override ExceptionHandler
to manage of sending nack/ack, which gives to us a full control.
Second: IMO simpler, solution is to set defaultRequeueRejected=false
and in converter throw ImmediateAcknowledgeAmqpException
. It makes that RabbitMQ
think that answer was accepted (the same thing as in case of first solution), moreover listener wouldn't be invoked.
**Conclusion**: Using
ImmediateAcknowledgeAmqpExceptionor
ExceptionHandler` exception we have a full control on permanent rejecting message (under hood ack) and resending to DLX.
回答1:
RabbitMQ knows nothing about the exceptions.
When the container catches an exception it calls channel.basicReject(deliveryTag, requeue)
.
If requeue is true, the message is requeued.
By default, for any exception other than those mentioned here
o.s.amqp...MessageConversionException
o.s.messaging...MessageConversionException
o.s.messaging...MethodArgumentNotValidException
o.s.messaging...MethodArgumentTypeMismatchException
java.lang.NoSuchMethodException
java.lang.ClassCastException
requeue
is set to true, so the message is requeued.
For those exceptions, the delivery is considered fatal and the message is NOT requeued, it will go to a DLX/DLQ if one is configured.
The container has a flag defaultRequeueRejected
which is true by default; if you set it to false
; no exceptions will be requeued.
For application-level exceptions, generally, messages will be requeued. To dynamically reject (and not requeue) a message, make sure there is an AmqpRejectAndDontRequeueException
in the cause chain. This instructs the container to not requeue the message, and it will go to the DLX/DLQ (if configured). This behavior is enabled by the defaultRequeueRejected
flag mentioned above.
This is all explained in the documentation and, as I have discussed in other answers to you, you can change this behavior by using a custom error handler; that, too, is explained in the documentation.
It is not possible to send some exceptions to the DLX/DLQ and not others; rabbit only has a binary option, requeue or don't requeue and, for the latter, if a DLX/DLQ is configured all such rejected messages go to the DLX/DLQ.
Spring AMQP provides one more exception, ImmediateAcknowledgeAmqpException
. If your listener throws this exception, the message will be ack'd as if it was processed successfully (channel.basicAck()
). That is the only technique provided by the container, to discard a bad message without sending it to the DLX/DLQ.
Of course, your application can drop such messsages itself.
If you want to DLX/DLQ all business exceptions but drop conversion exceptions, throw AmqpRejectAndDontRequeueException
(or set defaultRequeueRejected
to false), and throw ImmediateAcknowledgeAmqpException
from your converter.
来源:https://stackoverflow.com/questions/43018932/dlx-in-rabbitmq-and-spring-rabbitmq-some-considerations-of-rejecting-messages