做公司網(wǎng)站有沒有必要信息發(fā)布推廣平臺(tái)
前言
在編寫應(yīng)用程序時(shí),有時(shí)候會(huì)遇到一些短暫的錯(cuò)誤,例如網(wǎng)絡(luò)請(qǐng)求、服務(wù)鏈接終端失敗等,這些錯(cuò)誤可能導(dǎo)致函數(shù)執(zhí)行失敗。
但是如果稍后執(zhí)行可能會(huì)成功,那么在一些業(yè)務(wù)場(chǎng)景下就需要重試了,重試的概念很簡(jiǎn)單,這里就不做過多闡述了
最近也正好在轉(zhuǎn)golang語(yǔ)言,重試機(jī)制正好可以拿來練手,重試功能一般需要支持以下參數(shù)
- execFunc:需要被執(zhí)行的重試的函數(shù)
- interval:重試的間隔時(shí)長(zhǎng)
- attempts:嘗試次數(shù)
- conditionMode:重試的條件模式,error和bool模式(這個(gè)參數(shù)用于控制傳遞的執(zhí)行函數(shù)返回值類型檢測(cè)
代碼
package retryimplimport ("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í)長(zhǎng)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 對(duì)外暴露的執(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 對(duì)外暴露知的執(zhí)行函數(shù)可以返回?cái)?shù)據(jù)
func (r *RetryV2) DoV2WithData(execWithDataFunc RetryFuncWithData) (any, error) {fmt.Println("[Retry.DoV2WithData] begin execute func...")n := 0for n < r.attempts {res, err := execWithDataFunc()if err == nil {return res, nil}n++time.Sleep(r.interval)}return nil, nil
}
測(cè)試驗(yàn)證
package retryimplimport ("errors""fmt""testing""time"
)// TestRetryV2_DoFunc
func TestRetryV2_DoFunc(t *testing.T) {testSuites := []struct {exceptExecCount intactualExecCount 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 intresMessage 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)}}
參考:GitCode - 開發(fā)者的代碼家園