? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?原創(chuàng)者:文思
網(wǎng)絡(luò)資料(基本方向):
1:當出現(xiàn)異常時六荒,我們需要把這個消息回滾到消息隊列要么拋棄此消息:
2:經(jīng)過開發(fā)中的實際測試蠢琳,當讓消息回滾到消息隊列時,這條消息不會回到隊列尾部葡秒,而是仍是在隊列頭部双吆,這時消費者會立馬又接收到這條消息羞秤,進行處理鞠抑,接著拋出異常,進行回滾嫌吠,如此反復(fù)進行。這種情況會導(dǎo)致消息隊列處理出現(xiàn)阻塞掺炭,消息堆積辫诅,導(dǎo)致正常消息也無法運行。對于消息回滾到消息隊列涧狮,我們希望比較理想的方式時出現(xiàn)異常的消息到達消息隊列尾部炕矮,這樣既保證消息不會丟失么夫,又保證了正常業(yè)務(wù)的進行,因此我們采取的解決方案是肤视,將消息進行應(yīng)答档痪,這時消息隊列會刪除該消息,同時我們再次發(fā)送該消息到消息隊列邢滑,這時就實現(xiàn)了錯誤消息進行消息隊列尾部的方案腐螟。
實際應(yīng)用:
在做jodconvert結(jié)合mq進行文檔異步轉(zhuǎn)換時,因在process函數(shù)中沒有捕獲convert方法(文檔轉(zhuǎn)換時的方法)中拋出的異常困后,導(dǎo)致mq的消費方(process函數(shù))接收消息消費時失敗->返回隊列第一位->執(zhí)行->消費失敗->返回隊列第一位,如此反復(fù)導(dǎo)致后續(xù)mq消息被阻塞無法接收執(zhí)行乐纸,用catch()捕獲異常后,線應(yīng)答成功摇予,不會再次進入隊列執(zhí)行汽绢,解決。
以此總結(jié)出mq自動應(yīng)答的1個知識點:
Spring 與RabbitMq集成對消息的處理方式是默認自動應(yīng)答(百度)侧戴,但是mq消息消費與否的標志宁昭,網(wǎng)絡(luò)上百度出來的資料有些是錯誤的,現(xiàn)在通過程序來進行驗證和判斷酗宋,結(jié)論是:以process函數(shù)是否拋出異郴蹋或者異常是否被catch捕獲為標準,以下是程序推論:
在使用mq消息進行業(yè)務(wù)處理的過程中本缠,也就是使用消息進行業(yè)務(wù)處理的時候(convertUrl = queueBusinessHandlerService.ms2pdfByQueueExternalUtil(inputUrl))斥扛,什么情況下系統(tǒng)會認為消息消費不會失敗,已經(jīng)應(yīng)答了呢丹锹,現(xiàn)在驗證異常依次上拋稀颁,在最外層捕獲(異常一定要依次通過throw拋出,否則程序就因為發(fā)生異常而中斷):
1
1.1
1.1.
1.1.1
1.1.1.1
從1.1.1.1依次上拋到1
然后在最外層捕獲:
通過命令行看日志可以看到楣黍,不會再執(zhí)行那條mq記錄了匾灶,也就說明:
當convertUrl = queueBusinessHandlerService.ms2pdfByQueueExternalUtil(inputUrl)拋出異常時被catch捕獲,則process方法會認為消息消費成功租漂,因為異常被捕獲了嘛阶女,process程序體沒有中斷,執(zhí)行完了哩治,所以認為消費成功秃踩,進行了自動應(yīng)答,即使業(yè)務(wù)函數(shù)處理失敗了业筏,也不在會出現(xiàn)隊列中了憔杨。
如果需要對失敗的記錄進行處理,建議在catch{}中:
//手動進行應(yīng)答channel.basicAck(msg.getMessageProperties().getDeliveryTag(), false);
//重新發(fā)送消息到隊列尾部channel.basicPublish(message.getMessageProperties().getReceivedExchange(),message.getMessageProperties().getReceivedRoutingKey(), MessageProperties.PERSISTENT_TEXT_PLAIN,JSON.toJSONBytes(new Object()));
不需要再次處理的就不用管了蒜胖。
什么情況下算消費失敗消别,沒有應(yīng)答成功呢抛蚤,如果不在process中捕獲異常,或者在try{}catch(){}以外的地方發(fā)生異常寻狂,如下:
process中報了異常且沒有被catch捕獲岁经,則process認為消息接收時出現(xiàn)錯誤,沒有消費成功蛇券,則自動返回到隊里第一位缀壤,再次重復(fù)執(zhí)行:
.
反復(fù)回到隊列重復(fù)執(zhí)行...
.
在使用spring boot時,默認的是自動應(yīng)答怀读,如果想手工應(yīng)答诉位,在application.propretes中:
spring.rabbitmq.listener.acknowledge-mode=manual
則:
mq順利執(zhí)行完沒有報錯,但再次發(fā)送mq:
無法接收到新的mq消息菜枷。就需要在程序中進行手工消息應(yīng)該操作: