Golang三種方式實現(xiàn)超時退出

問題

前段時間發(fā)現(xiàn)線上有個服務(wù)接口钓葫,總是間歇性告警威兜,有時候一天兩三次嚎尤,有時候一天都沒有。

告警的邏輯是在一個接口中異步調(diào)用了另一個HTTP接口伞鲫,這個HTTP接口調(diào)用出現(xiàn)超時库物。但是我去問了負(fù)責(zé)這個HTTP接口的同學(xué)霸旗,人家說他們的接口相應(yīng)都是毫秒級別,還截圖監(jiān)控了戚揭,有圖有真相诱告,我還能說啥。

但是民晒,超時是確實存在的精居,只是請求還可能沒有到人家服務(wù)那邊锄禽。

這種偶發(fā)性問題不好復(fù)現(xiàn),偶爾來個告警也挺煩的靴姿,第一反應(yīng)還是先解決問題沃但,思路也簡單,失敗后重試佛吓。

解決方法

且不談重試策略宵晚,先說說什么時候觸發(fā)重試。

我們可以在接口請求出錯拋出err的時候重試维雇,但是這種不好控制淤刃,如果一個請求出去,十來秒都沒有響應(yīng)吱型,則這個協(xié)程就要傻傻的等他報錯才能重試逸贾,浪費生命啊~

所以結(jié)合上面同學(xué)給出的毫秒級響應(yīng)指標(biāo),可以設(shè)定一個超時時間津滞,如果在指定超時時間后沒有返回結(jié)果铝侵,則重試(這篇重試不是重點)。

func AsyncCall() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*800))
    defer cancel()
    go func(ctx context.Context) {
        // 發(fā)送HTTP請求
    }()

    select {
    case <-ctx.Done():
        fmt.Println("call successfully!!!")
        return
    case <-time.After(time.Duration(time.Millisecond * 900)):
        fmt.Println("timeout!!!")
        return
    }
}

說明

1据沈、通過context的WithTimeout設(shè)置一個有效時間為800毫秒的context哟沫。

2、該context會在耗盡800毫秒后或者方法執(zhí)行完成后結(jié)束锌介,結(jié)束的時候會向通道ctx.Done發(fā)送信號嗜诀。

3、有人可能要問孔祸,你這里已經(jīng)設(shè)置了context的有效時間隆敢,為什么還要加上這個time.After呢?

這是因為該方法內(nèi)的context是自己申明的崔慧,可以手動設(shè)置對應(yīng)的超時時間拂蝎,但是在大多數(shù)場景,這里的ctx是從上游一直傳遞過來的惶室,對于上游傳遞過來的context還剩多少時間温自,我們是不知道的,所以這時候通過time.After設(shè)置一個自己預(yù)期的超時時間就很有必要了皇钞。

4悼泌、注意,這里要記得調(diào)用cancel()夹界,不然即使提前執(zhí)行完了馆里,還要傻傻等到800毫秒后context才會被釋放。

總結(jié)

上面的超時控制是搭配使用了ctx.Done和time.After。

Done通道負(fù)責(zé)監(jiān)聽context啥時候完事鸠踪,如果在time.After設(shè)置的超時時間到了丙者,你還沒完事,那我就不等了营密,執(zhí)行超時后的邏輯代碼械媒。

舉一反三

那么,除了上面這種超時控制策略卵贱,還有其他的套路嗎滥沫?

有,但是大同小異键俱。

第一種:使用time.NewTimer

func AsyncCall() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond * 800))
    defer cancel()
    timer := time.NewTimer(time.Duration(time.Millisecond * 900))

    go func(ctx context.Context) {
        // 發(fā)送HTTP請求
    }()

    select {
    case <-ctx.Done():
        timer.Stop()
        timer.Reset(time.Second)
        fmt.Println("call successfully!!!")
        return
    case <-timer.C:
        fmt.Println("timeout!!!")
        return
    }
}

這里的主要區(qū)別是將time.After換成了time.NewTimer,也是同樣的思路如果接口調(diào)用提前完成世分,則監(jiān)聽到Done信號编振,然后關(guān)閉定時器。

否則的話臭埋,會在指定的timer即900毫秒后執(zhí)行超時后的業(yè)務(wù)邏輯踪央。

第二種:使用通道

func AsyncCall() {
  ctx := context.Background()
    done := make(chan struct{}, 1)

    go func(ctx context.Context) {
        // 發(fā)送HTTP請求
        done <- struct{}{}
    }()

    select {
    case <-done:
        fmt.Println("call successfully!!!")
        return
    case <-time.After(time.Duration(800 * time.Millisecond)):
        fmt.Println("timeout!!!")
        return
    }
}

1、這里主要利用通道可以在協(xié)程之間通信的特點瓢阴,當(dāng)調(diào)用成功后畅蹂,向done通道發(fā)送信號。

2荣恐、監(jiān)聽Done信號液斜,如果在time.After超時時間之前接收到叠穆,則正常返回少漆,否則走向time.After的超時邏輯,執(zhí)行超時邏輯代碼硼被。

3示损、這里使用的是通道和time.After組合,也可以使用通道和time.NewTimer組合嚷硫。

總結(jié)

本篇主要介紹如何實現(xiàn)超時控制检访,主要有三種

1、context.WithTimeout/context.WithDeadline + time.After

2仔掸、context.WithTimeout/context.WithDeadline + time.NewTimer

3脆贵、channel + time.After/time.NewTimer

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市嘉汰,隨后出現(xiàn)的幾起案子丹禀,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件双泪,死亡現(xiàn)場離奇詭異持搜,居然都是意外死亡,警方通過查閱死者的電腦和手機焙矛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門葫盼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人村斟,你說我怎么就攤上這事贫导。” “怎么了蟆盹?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵孩灯,是天一觀的道長。 經(jīng)常有香客問我逾滥,道長峰档,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任寨昙,我火速辦了婚禮讥巡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘舔哪。我一直安慰自己欢顷,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布捉蚤。 她就那樣靜靜地躺著抬驴,像睡著了一般。 火紅的嫁衣襯著肌膚如雪外里。 梳的紋絲不亂的頭發(fā)上怎爵,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天,我揣著相機與錄音盅蝗,去河邊找鬼鳖链。 笑死,一個胖子當(dāng)著我的面吹牛墩莫,可吹牛的內(nèi)容都是我干的芙委。 我是一名探鬼主播,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼狂秦,長吁一口氣:“原來是場噩夢啊……” “哼灌侣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起裂问,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤侧啼,失蹤者是張志新(化名)和其女友劉穎牛柒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體痊乾,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡皮壁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了哪审。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蛾魄。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖湿滓,靈堂內(nèi)的尸體忽然破棺而出滴须,到底是詐尸還是另有隱情,我是刑警寧澤叽奥,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布扔水,位于F島的核電站,受9級特大地震影響朝氓,放射性物質(zhì)發(fā)生泄漏铭污。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一膀篮、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧岂膳,春花似錦誓竿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至簸喂,卻和暖如春毙死,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喻鳄。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工扼倘, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人除呵。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓再菊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親颜曾。 傳聞我的和親對象是個殘疾皇子纠拔,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容