精講響應式WebClient第6篇-請求失敗自動重試機制侧但,強烈建議你看一看

精講響應式WebClient第6篇-請求失敗自動重試機制

本文是精講響應式WebClient第6篇皮壁,前篇的blog訪問地址如下:

在上一篇我們?yōu)榇蠹医榻B了WebClient的異常處理方法窜骄,我們可以對指定的異常進行處理锦募,也可以分類處理400-499、500-599狀態(tài)碼的HTTP異常邻遏。
我們本節(jié)為大家介紹的實際上是另外一種異常處理機制:請求失敗之后自動重試糠亩。當WebClient發(fā)起請求虐骑,沒有得到正常的響應結(jié)果,它就會每隔一段時間再次發(fā)送請求赎线,可以發(fā)送n次廷没,這個n是我們自定義的。n次請求都失敗了垂寥,最后再將異常拋出颠黎,可以通過我們上一節(jié)交給大家的方法進行異常處理。也就是針對連接超時異常滞项、讀寫超時異常等狭归,或者是HTTP響應結(jié)果為非正常狀態(tài)碼(不是200狀態(tài)碼段),都在自動重試機制的范疇內(nèi)文判。

如果您覺得我的文章對您有幫助的話过椎,請幫忙點贊或分享,您的支持是我不竭的創(chuàng)作動力戏仓!

一疚宇、請求異常重試

下面的代碼是請求"http://jsonplaceholder.typicode.com" 網(wǎng)站的服務,該網(wǎng)站是一個免費提供HTTP請求測試的服務端網(wǎng)站柜去,我們可以用它測試WebClient灰嫉。需要注意的是:正常的GET方法請求地址是"/posts/1",我特意的把它寫錯成為"/postss/1"嗓奢,這樣可以觸發(fā)404資源無法找到的異常。

public class ReTryTest {
  
  @Test
  public void testRetry() {
    WebClient webClient = WebClient.builder()
            .baseUrl("http://jsonplaceholder.typicode.com")
            .build();

    Mono<String> mono = webClient
            .get()  //GET 請求
            .uri("/postss/1")  // 請求路徑,注意為了制造異常浑厚,這里是錯的
            .retrieve()  //獲取請求結(jié)果
            .bodyToMono(String.class)  //用Mono接收單個非集合對象數(shù)據(jù)
            .doOnError(Exception.class, err -> {  //處理異常
              System.out.println(LocalDateTime.now() +  "---發(fā)生錯誤:" +err.getMessage() );
            })
            .retry(3);

    System.out.println("=====" + mono.block());
  }
  
}
  • doOnError異常處理是我們在上一節(jié)文章中為大家介紹的異常處理函數(shù)股耽,我們在這里打印日志,觀察重試次數(shù)
  • retry(3)就是重點了钳幅,表示請求失敗之后重試3次請求物蝙。也可以使用retry()無參方法,不設(shè)置次數(shù)敢艰,可以無限重試诬乞。這樣顯然不好,我們一般不用钠导。

下面是doOnError中打印的控制臺輸出內(nèi)容震嫉,一共打印了4次。(一次失敗 + 三次重試失斈凳簟)


二票堵、重試時間間隔設(shè)置

上面的請求重試方法,請求失敗之后立即重試逮栅,在很短的時間內(nèi)就完成了3次重試悴势。如果這是在生產(chǎn)環(huán)境下窗宇,可能你的服務端因為資源緊張造成請求響應超時等異常,這種重試機制無疑會讓本就不堪重負的服務端雪上加霜特纤。我們下面交給大家一種為重試設(shè)置時間間隔的方法:

.retryBackoff(3, Duration.ofSeconds(5));
  • 第一個參數(shù)仍然表示重試3次
  • 第二個參數(shù)表示按指數(shù)增長的時間間隔重試军俊,第一次重試間隔5秒,第二次間隔10秒(5 x2)捧存,第三次間隔20秒(5x2x2)

源碼如下:

三粪躬、retryWhen方法

上面的retryBackoff方法雖然已經(jīng)一定程度上緩解了請求重試導致的服務端的壓力,但是它還是不分場景的不斷重試矗蕊。

  • 在實際的開發(fā)中短蜕,可以請求重試的場景應該是:網(wǎng)絡異常、請求超時異常傻咖、服務端突然面臨高并發(fā)導致的臨時處理能力不足導致的超時等這種由于外部原因?qū)е碌漠惓鼍啊?/li>
  • 對于那些由于程序員編寫的bug朋魔、資源訪問權(quán)限不足、資源找不到卿操、HTTP版本不受支持等造成的異常警检,重試一萬次也不會成功,反而可能因為你不斷的重試造成服務器崩潰害淤。

所以說Webclient已經(jīng)在源碼中扇雕,將retryBackoff()標記為廢棄,建議使用retryWhen()代替它窥摄。retryWhen()可以指定針對某些異常進行重試镶奉,其他異常不做重試。


為了使用retryWhen(),需要引入下面的包

<dependency>
   <groupId>io.projectreactor.addons</groupId>
   <artifactId>reactor-extra</artifactId>
</dependency>

3.1.人為制造超時異常-用于測試

為了能夠制造請求超時的異常場景崭放,我們給連接超時設(shè)置為5毫秒哨苛,即:讓所有請求一定會超時。(沒有任何請求能在5毫秒內(nèi)完成網(wǎng)絡連接)

//認為設(shè)置請求超時時間為5毫秒币砂,也就是請求一定會超時建峭,一定會拋出ConnectTimeoutException
TcpClient tcpClient = TcpClient
        .create()
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5); //5毫秒

WebClient webClient = WebClient.builder()
        .baseUrl("http://jsonplaceholder.typicode.com")
        .clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient)))
        .build();

3.2.測試retryWhen

用Retry對象定義請求重試的條件,也就是retryWhen的when

Retry<?> retry = Retry.onlyIf(x -> x.exception() instanceof ConnectTimeoutException)
        .retryMax(3) // 重試3次
        .backoff(Backoff.exponential(Duration.ofSeconds(5),Duration.ofSeconds(60),2,true));

Mono<String> mono = webClient
        .get()    //GET 請求
        .uri("/posts/1")  // 請求路徑,這里的請求路徑是正確的
        .retrieve()
        .bodyToMono(String.class)
        .retryWhen(retry);   //滿足Retry條件進行重試

System.out.println("=====" + mono.block());
  • Retry.onlyIf(x -> x.exception() instanceof ConnectTimeoutException) 表示只有針對ConnectTimeoutException連接超市異常才進行請求重試决摧,這里使用了java8的Predicate語法
  • Backoff.exponential表示按指數(shù)增長的時間間隔進行重試亿蒸,可以自己指定指數(shù)重試因子,即指數(shù)的計數(shù)掌桩。這里我們?nèi)匀皇褂?作為指數(shù)重試因子边锁,第一次重試間隔5秒,第二次間隔10秒(5 x2)拘鞋,第三次間隔20秒(5x2x2)
  • 為防止間隔時間指數(shù)級無限延長砚蓬,Backoff.exponential最長的重試間隔不能超過60秒,第二個參數(shù)盆色。
  • retryWhen(retry) 滿足retry條件進行重試

3.3.retryWhen的其他方法

  • onlyIf()表示捕獲到指定的某個異常灰蛙,進行請求重試
  • allBut()表示除了某個異常之外祟剔,其他的異常被捕獲則進行請求重試
  • any() 表示針對所有異常,進行請求重試
  • anyOf()表示指定某些異常類型摩梧,進行請求重試

backOff表示重試的時間間隔

  • exponential()指數(shù)級增長的時間間隔
  • fix()表示固定的時間間隔

歡迎關(guān)注我的博客物延,里面有很多精品合集

  • 本文轉(zhuǎn)載注明出處(必須帶連接,不能只轉(zhuǎn)文字):字母哥博客仅父。

覺得對您有幫助的話叛薯,幫我點贊、分享笙纤!您的支持是我不竭的創(chuàng)作動力耗溜! 。另外省容,筆者最近一段時間輸出了如下的精品內(nèi)容抖拴,期待您的關(guān)注。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腥椒,一起剝皮案震驚了整個濱河市阿宅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌笼蛛,老刑警劉巖洒放,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滨砍,居然都是意外死亡往湿,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門惋戏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來煌茴,“玉大人,你說我怎么就攤上這事日川。” “怎么了矩乐?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵龄句,是天一觀的道長。 經(jīng)常有香客問我散罕,道長分歇,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任欧漱,我火速辦了婚禮职抡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘误甚。我一直安慰自己缚甩,他們只是感情好谱净,可當我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著擅威,像睡著了一般壕探。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上郊丛,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天李请,我揣著相機與錄音,去河邊找鬼厉熟。 笑死导盅,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的揍瑟。 我是一名探鬼主播白翻,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼月培!你這毒婦竟也來了嘁字?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤杉畜,失蹤者是張志新(化名)和其女友劉穎纪蜒,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體此叠,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡纯续,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了灭袁。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片猬错。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖茸歧,靈堂內(nèi)的尸體忽然破棺而出倦炒,到底是詐尸還是另有隱情,我是刑警寧澤软瞎,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布逢唤,位于F島的核電站,受9級特大地震影響涤浇,放射性物質(zhì)發(fā)生泄漏鳖藕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一只锭、第九天 我趴在偏房一處隱蔽的房頂上張望著恩。 院中可真熱鬧,春花似錦、人聲如沸喉誊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽裹驰。三九已至隧熙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間幻林,已是汗流浹背贞盯。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沪饺,地道東北人躏敢。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像整葡,于是被迫代替她去往敵國和親件余。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,678評論 2 354