前言
在编写应用程序时,有时候会遇到一些短暂的错误,例如网络请求、服务链接终端失败等,这些错误可能导致函数执行失败。
但是如果稍后执行可能会成功,那么在一些业务场景下就需要重试了,重试的概念很简单,这里就不做过多阐述了
最近也正好在转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: defaultattempts,
}
for _, opt := range opts {
opt(&retry)
}
return &retry
}
// withintervalv2 重试的时间间隔配置
func withintervalv2(interval time.duration) retryoptionv2 {
return func(retry *retryv2) {
retry.interval = interval
}
}
// withattemptsv2 重试的次数
func withattemptsv2(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
}
// dov2withdata 对外暴露知的执行函数可以返回数据
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 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)
}
}到此这篇关于golang函数重试机制实现的文章就介绍到这了,更多相关golang重试机制内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论