問題描述
我確實閱讀了此參考:https://www.rabbitmq.com/dlx.html,但它并沒有解決我的疑問,即:
如果接受消息沒有問題 - spring-rabbitmq
發送確認并且一切都很好,DLX
不知道確認的消息.
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.
問題是如果拒絕回答,即拋出 MessageConverterException
怎么辦?此消息已刪除或移至 DLX
?
The problem is in case rejecting answer, namely what about throwing MessageConverterException
? This message is removed or moved to DLX
?
如果有其他異常怎么辦?例如 Exception
?它被刪除/重新排隊/移動到 DLX
?
And what about in case other exception ? For example Exception
? It is removed/requeued/moved to DLX
?
@Gary 回答后編輯
我認為,在回答@Gary 之后,我應該添加更多關于我的案例的詳細信息以及@Gary 回答的一些摘要.@Gary 完全掌握了我的用例.
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.
我不喜歡重新排隊 - 從不(我害怕循環),但我不希望在拋出異常時丟失消息(例如失去與數據庫的連接) - 此消息應該重新發送到 DLX代碼>.另一方面,消息的轉換應該被視為致命錯誤 - 沒有重新排隊,沒有重新發送到 DLX - 只是永久刪除消息.通常,取決于異常拒絕(=重新發送到 DLX,如果已配置)或接受,從不重新排隊.
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.
簡而言之,@Gary 提出的方法.
首先:我們可以重寫ExceptionHandler
來管理發送nack/ack,這給了我們一個完全的控制權.
第二:IMO更簡單,解決方案是設置defaultRequeueRejected=false
并在轉換器中拋出ImmediateAcknowledgeAmqpException
.它使 RabbitMQ
認為答案已被接受(與第一個解決方案的情況相同),而且不會調用偵聽器.<代碼>**結論**:使用ImmediateAcknowledgeAmqpException或
ExceptionHandler`異常,我們可以完全控制永久拒絕消息(在后臺確認)并重新發送到DLX.
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.
推薦答案
RabbitMQ 對異常一無所知.
RabbitMQ knows nothing about the exceptions.
當容器捕獲到異常時,它會調用 channel.basicReject(deliveryTag, requeue)
.
When the container catches an exception it calls channel.basicReject(deliveryTag, requeue)
.
如果 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.amqp...MessageConversionException
o.s.messaging...MessageConversionException
o.s.messaging...MessageConversionException
o.s.messaging...MethodArgumentNotValidException
o.s.messaging...MethodArgumentNotValidException
o.s.messaging...MethodArgumentTypeMismatchException
o.s.messaging...MethodArgumentTypeMismatchException
java.lang.NoSuchMethodException
java.lang.NoSuchMethodException
java.lang.ClassCastException
java.lang.ClassCastException
requeue
設置為 true,因此消息被重新排隊.
requeue
is set to true, so the message is requeued.
對于那些例外,傳遞被認為是致命的并且消息不會重新排隊,如果配置了一個,它將轉到 DLX/DLQ.
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.
容器有一個標志defaultRequeueRejected
,默認為true;如果您將其設置為 false
;不會重新排隊任何異常.
The container has a flag defaultRequeueRejected
which is true by default; if you set it to false
; no exceptions will be requeued.
對于應用程序級別的異常,通常會重新排隊消息.要動態拒絕(而不是重新排隊)消息,請確保原因鏈中存在 AmqpRejectAndDontRequeueException
.這指示容器不要重新排隊消息,它將轉到 DLX/DLQ(如果已配置).此行為由上面提到的 defaultRequeueRejected
標志啟用.
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.
無法將某些異常發送到 DLX/DLQ 而不是其他;rabbit 只有一個二元選項,requeue 或 don't requeue,對于后者,如果配置了 DLX/DLQ,所有此類被拒絕的消息都會轉到 DLX/DLQ.
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 提供了另一種異常,ImmediateAcknowledgeAmqpException
.如果您的偵聽器拋出此異常,則消息將被確認,就好像它已成功處理一樣 (channel.basicAck()
).這是容器提供的唯一技術,可以丟棄壞消息而不將其發送到 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.
如果要DLX/DLQ所有業務異常但丟棄轉換異常,拋出AmqpRejectAndDontRequeueException
(或設置defaultRequeueRejected
為false),并拋出ImmediateAcknowledgeAmqpException代碼>來自您的轉換器.
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.
這篇關于rabbitmq 和 spring-rabbitmq 中的 DLX - 拒絕消息的一些注意事項的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!