一个简单而强大的 Go 语言库,用于实现各种重试机制,支持多种延迟策略、错误处理和自定义配置。
使用 Go 模块安装:
go get cnb.cool/zhiqiangwang/pkg/retry-go
import "cnb.cool/zhiqiangwang/pkg/retry-go"
func main() {
err := retry.Do(func() error {
// 执行可能失败的操作
return someOperation()
})
if err != nil {
// 处理错误
}
}
import "cnb.cool/zhiqiangwang/pkg/retry-go"
func main() {
result, err := retry.DoWithData(func() (string, error) {
// 执行可能失败的操作并返回数据
return someOperationWithResult()
})
if err != nil {
// 处理错误
}
// 使用结果
fmt.Println(result)
}
// 最多重试 5 次
err := retry.Do(func() error {
return someOperation()
}, retry.Attempts(5))
// 无限重试,直到成功
err := retry.Do(func() error {
return someOperation()
}, retry.UntilSucceeded())
// 固定延迟
err := retry.Do(func() error {
return someOperation()
}, retry.Delay(100*time.Millisecond), retry.DelayType(retry.FixedDelay))
// 指数退避延迟
err := retry.Do(func() error {
return someOperation()
}, retry.Delay(100*time.Millisecond), retry.DelayType(retry.BackOffDelay))
// 带抖动的指数退避延迟
err := retry.Do(func() error {
return someOperation()
}, retry.Delay(100*time.Millisecond), retry.DelayType(retry.FullJitterBackoffDelay))
// 组合延迟策略
err := retry.Do(func() error {
return someOperation()
}, retry.Delay(100*time.Millisecond), retry.MaxJitter(50*time.Millisecond), retry.DelayType(retry.CombineDelay(retry.BackOffDelay, retry.RandomDelay)))
testErr := errors.New("temporary error")
err := retry.Do(func() error {
if condition {
return testErr
}
return someOperation()
}, retry.AttemptsForError(3, testErr))
err := retry.Do(func() error {
return someOperation()
}, retry.OnRetry(func(attempt uint, err error) {
fmt.Printf("Attempt %d failed: %v\n", attempt, err)
}))
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
err := retry.Do(func() error {
return someOperation()
}, retry.Context(ctx))
// 标记错误为不可恢复,遇到此错误将不再重试
err := retry.Do(func() error {
if fatalCondition {
return retry.Unrecoverable(errors.New("fatal error"))
}
return someOperation()
})
// 只返回最后一个错误
err := retry.Do(func() error {
return someOperation()
}, retry.LastErrorOnly(true))
| 策略 | 描述 |
|---|---|
FixedDelay | 固定延迟时间 |
BackOffDelay | 指数退避延迟 |
RandomDelay | 随机延迟 |
FullJitterBackoffDelay | 带抖动的指数退避延迟 |
CombineDelay | 组合多种延迟策略 |
运行测试:
go test -v
import (
"cnb.cool/zhiqiangwang/pkg/retry-go"
"fmt"
"io"
"net/http"
"time"
)
func fetchData(url string) (string, error) {
var data string
err := retry.Do(func() error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
// 检查 HTTP 状态码
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status code: %d", resp.StatusCode)
}
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
data = string(body)
return nil
},
retry.Attempts(3), // 最多重试 3 次
retry.Delay(1*time.Second), // 基础延迟 1 秒
retry.MaxDelay(10*time.Second), // 最大延迟 10 秒
retry.DelayType(retry.BackOffDelay), // 使用指数退避延迟
retry.OnRetry(func(attempt uint, err error) {
fmt.Printf("Attempt %d failed: %v\n", attempt, err)
}))
return data, err
}
// 使用示例
func main() {
url := "https://api.example.com/data"
data, err := fetchData(url)
if err != nil {
fmt.Printf("Failed to fetch data: %v\n", err)
return
}
fmt.Printf("Fetched data: %s\n", data)
}
func connectDB(dsn string) (*sql.DB, error) {
var db *sql.DB
err := retry.Do(func() error {
var err error
db, err = sql.Open("mysql", dsn)
if err != nil {
return err
}
return db.Ping()
}, retry.Attempts(5), retry.Delay(2*time.Second), retry.DelayType(retry.BackOffDelay))
return db, err
}
Apache License 2.0