Retry-Go:Go 優雅重試

在 Go 語言的開發過程中,我們經常需要執行可能失敗的操作,比如網絡請求。如果每次失敗都直接報錯並終止程序,用戶體驗就會很差。通常的做法是重試,即在失敗後等待一段時間再嘗試重新執行。

retry-go (github.com/avast/retry-go) 是一個輕量級的 Go 語言重試庫,提供簡單易用的**「重試機制」**,支持:

安裝

go get github.com/avast/retry-go/v4

基本使用

以下示例展示瞭如何使用 retry-go 進行 HTTP 請求的自動重試:

 url := "http://example.com"
 var body []byte

 err := retry.Do(
  func() error {
   resp, err := http.Get(url)
   if err != nil {
    return err
   }
   defer resp.Body.Close()
   body, err = io.ReadAll(resp.Body)
   if err != nil {
    return err
   }
   return nil
  },
 )

 if err != nil {
  // 處理錯誤
 }

 fmt.Println(string(body))

帶返回數據的重試:

 url := "http://example.com"

 body, err := retry.DoWithData(
  func() ([]byte, error) {
   resp, err := http.Get(url)
   if err != nil {
    return nil, err
   }
   defer resp.Body.Close()
   body, err := io.ReadAll(resp.Body)
   if err != nil {
    return nil, err
   }
   return body, nil
  },
 )

 if err != nil {
  // 處理錯誤
 }

 fmt.Println(string(body))

默認重試策略

閱讀源碼後,我們可以看到默認配置:

  attempts:         uint(10),  // 默認最多重試 10 次
  delay:            100 * time.Millisecond, // 初始基礎間隔 100ms
  maxJitter:        100 * time.Millisecond, // 最大抖動 100ms
  delayType:        CombineDelay(BackOffDelay, RandomDelay), // 指數退避 + 隨機抖動

默認的設置不是固定間隔的重試,而是:指數退避增長(BackOffDelay)加上一個 0~100ms 的隨機抖動(RandomDelay)。默認最多重試 10 次。

最大重試次數

 retry.Do(
  task,
  retry.Attempts(5), // 最大重試 5 次
 )

如果設置成 retry.Attempts(0),無限重試,直到成功。

重試間隔

 retry.Do(
  task,
  retry.Delay(200*time.Millisecond), // 每次重試間隔 200 毫秒
 )

指數回退

 retry.Do(
  task,
  retry.DelayType(retry.BackOffDelay), // 指數回退策略
 )

隨機延遲

 retry.Do(
  task,
  retry.DelayType(retry.RandomDelay), // 隨機回退策略
 )

固定延遲

 retry.Do(
  task,
  retry.DelayType(retry.FixedDelay),
 )

超時控制

 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
 defer cancel()

 retry.Do(
  task,
  retry.Context(ctx),
 )

僅在特定錯誤時重試

當返回的錯誤值等於 retry.RetryIf() 中定義的條件時才進行重試。

 retry.Do(
  func() error {
   return errors.New("special error")
  },
  retry.RetryIf(func(err error) bool {
   return err.Error() == "special error"
  }),
 )

僅在特定錯誤時終止重試

當使用 retry.Unrecoverable() 包裹錯誤值後,返回這個錯誤時不會再進行重試。

 retry.Do(
  func() error {
   return retry.Unrecoverable(errors.New("special error"))
  },
 )

References
https://github.com/avast/retry-go

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/zehApJEFjm5CZB_RqOJF6A