前言
在编写应用程序时,有时候会遇到一些短暂的错误,例如网络请求、服务链接终端失败等,这些错误可能导致函数执行失败。
但是如果稍后执行可能会成功,那么在一些业务场景下就需要重试了,重试的概念很简单,这里就不做过多阐述了最近也正好在转golang语言,重试机制正好可以拿来练手,重试功能一般需要支持以下参数
- execFunc:需要被执行的重试的函数
- interval:重试的间隔时长
- attempts:尝试次数
- conditionMode:重试的条件模式,error和bool模式(这个参数用于控制传递的执行函数返回值类型检测
代码
package retryimpl import ( "fmt" "time" ) // RetryOptionV2 配置选项函数 type RetryOptionV2 func(retry *RetryV2) // RetryFunc 不带返回值的重试函数 type RetryFunc func() error // RetryFuncWithData 带返回值的重试函数 type RetryFuncWithData func() (any, error) // RetryV2 重试类 type RetryV2 struct { interval time.Duration // 重试的间隔时长 attempts int // 重试次数 } // NewRetryV2 构造函数 func NewRetryV2(opts ...RetryOptionV2) *RetryV2 { retry := RetryV2{ interval: DefaultInterval, attempts: Def编程客栈aultAttempts, } for _, opt := range opts { opt(&retry) } return &retry } // WithIntervalV2 重试的时间间隔配置 func WithIntervalV2(interval time.Duration) RetryOptionV2 { return func(retry *RetryV2) { retry.interval = interval } } // WithAttemptsV2 重试的次数 func WithAttemptsV编程2(attempts int) RetryOptionV2 { return func(retry *RetryV2) { retry.attempts = attempts } } // DoV2 对外暴露的执行函数 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 } // DoV2With编程Data 对外暴露知的执行函数可以返回数据 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 }
测试验证
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 javascript 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 - 开发者的代码家园
到此这篇关于Golang函数重试机制实现的文章就介绍到这了,更多相关Golang重试机制内容请搜索编程客栈(www.devze.com)以前的http://www.devze.com文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
精彩评论