Golang函數(shù)重試機(jī)制實(shí)現(xiàn)代碼
前言
在編寫應(yīng)用程序時(shí),有時(shí)候會遇到一些短暫的錯(cuò)誤,例如網(wǎng)絡(luò)請求、服務(wù)鏈接終端失敗等,這些錯(cuò)誤可能導(dǎo)致函數(shù)執(zhí)行失敗。
但是如果稍后執(zhí)行可能會成功,那么在一些業(yè)務(wù)場景下就需要重試了,重試的概念很簡單,這里就不做過多闡述了
最近也正好在轉(zhuǎn)golang語言,重試機(jī)制正好可以拿來練手,重試功能一般需要支持以下參數(shù)
- execFunc:需要被執(zhí)行的重試的函數(shù)
- interval:重試的間隔時(shí)長
- attempts:嘗試次數(shù)
- conditionMode:重試的條件模式,error和bool模式(這個(gè)參數(shù)用于控制傳遞的執(zhí)行函數(shù)返回值類型檢測
代碼
package retryimpl import ( "fmt" "time" ) // RetryOptionV2 配置選項(xiàng)函數(shù) type RetryOptionV2 func(retry *RetryV2) // RetryFunc 不帶返回值的重試函數(shù) type RetryFunc func() error // RetryFuncWithData 帶返回值的重試函數(shù) type RetryFuncWithData func() (any, error) // RetryV2 重試類 type RetryV2 struct { interval time.Duration // 重試的間隔時(shí)長 attempts int // 重試次數(shù) } // NewRetryV2 構(gòu)造函數(shù) func NewRetryV2(opts ...RetryOptionV2) *RetryV2 { retry := RetryV2{ interval: DefaultInterval, attempts: DefaultAttempts, } for _, opt := range opts { opt(&retry) } return &retry } // WithIntervalV2 重試的時(shí)間間隔配置 func WithIntervalV2(interval time.Duration) RetryOptionV2 { return func(retry *RetryV2) { retry.interval = interval } } // WithAttemptsV2 重試的次數(shù) func WithAttemptsV2(attempts int) RetryOptionV2 { return func(retry *RetryV2) { retry.attempts = attempts } } // DoV2 對外暴露的執(zhí)行函數(shù) func (r *RetryV2) DoV2(executeFunc RetryFunc) error { fmt.Println("[Retry.DoV2] begin execute func...") retryFuncWithData := func() (any, error) { return nil, executeFunc() } _, err := r.DoV2WithData(retryFuncWithData) return err } // DoV2WithData 對外暴露知的執(zhí)行函數(shù)可以返回?cái)?shù)據(jù) func (r *RetryV2) DoV2WithData(execWithDataFunc RetryFuncWithData) (any, error) { fmt.Println("[Retry.DoV2WithData] begin execute func...") n := 0 for n < r.attempts { res, err := execWithDataFunc() if err == nil { return res, nil } n++ time.Sleep(r.interval) } return nil, nil }
測試驗(yàn)證
package retryimpl import ( "errors" "fmt" "testing" "time" ) // TestRetryV2_DoFunc func TestRetryV2_DoFunc(t *testing.T) { testSuites := []struct { exceptExecCount int actualExecCount int }{ {exceptExecCount: 3, actualExecCount: 0}, {exceptExecCount: 1, actualExecCount: 1}, } for _, testSuite := range testSuites { retry := NewRetryV2( WithAttemptsV2(testSuite.exceptExecCount), WithIntervalV2(1*time.Second), ) err := retry.DoV2(func() error { fmt.Println("[TestRetry_DoFuncBoolMode] was called ...") if testSuite.exceptExecCount == 1 { return nil } testSuite.actualExecCount++ return errors.New("raise error") }) if err != nil { t.Errorf("[TestRetryV2_DoFunc] retyr.DoV2 execute failed and err:%+v", err) continue } if testSuite.actualExecCount != testSuite.exceptExecCount { t.Errorf("[TestRetryV2_DoFunc] got actualExecCount:%v != exceptExecCount:%v", testSuite.actualExecCount, testSuite.exceptExecCount) } } } // TestRetryV2_DoFuncWithData func TestRetryV2_DoFuncWithData(t *testing.T) { testSuites := []struct { exceptExecCount int resMessage string }{ {exceptExecCount: 3, resMessage: "fail"}, {exceptExecCount: 1, resMessage: "ok"}, } for _, testSuite := range testSuites { retry := NewRetryV2( WithAttemptsV2(testSuite.exceptExecCount), WithIntervalV2(1*time.Second), ) res, err := retry.DoV2WithData(func() (any, error) { fmt.Println("[TestRetryV2_DoFuncWithData] DoV2WithData was called ...") if testSuite.exceptExecCount == 1 { return testSuite.resMessage, nil } return testSuite.resMessage, errors.New("raise error") }) if err != nil { t.Errorf("[TestRetryV2_DoFuncWithData] retyr.DoV2 execute failed and err:%+v", err) continue } if val, ok := res.(string); ok && val != testSuite.resMessage { t.Errorf("[TestRetryV2_DoFuncWithData] got unexcept result:%+v", val) continue } t.Logf("[TestRetryV2_DoFuncWithData] got result:%+v", testSuite.resMessage) } }
到此這篇關(guān)于Golang函數(shù)重試機(jī)制實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Golang重試機(jī)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang連接mysql數(shù)據(jù)庫操作使用示例
這篇文章主要為大家介紹了golang連接mysql數(shù)據(jù)庫操作使用示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04深入了解Golang網(wǎng)絡(luò)編程N(yùn)et包的使用
net包主要是增加?context?控制,封裝了一些不同的連接類型以及DNS?查找等等,同時(shí)在有需要的地方引入?goroutine?提高處理效率。本文主要和大家分享下在Go中網(wǎng)絡(luò)編程的實(shí)現(xiàn),需要的可以參考一下2022-07-07利用systemd部署golang項(xiàng)目的實(shí)現(xiàn)方法
這篇文章主要介紹了利用systemd部署golang項(xiàng)目的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11Go項(xiàng)目中添加生成時(shí)間與版本信息的方法
本文主要介紹了Go項(xiàng)目中添加生成時(shí)間與版本信息的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04