golang简单高效的失败重试机制插件库retry的使用
golang简单高效的失败重试机制插件库retry的使用
Retry是一个非常简单易用的库,可以确保您的工作能够完成。
特性
- 重试运行工作流程(例如RPC或数据库访问)
- 自定义回退策略
- 根据错误类型进行重试
使用示例
下面是一个完整的示例demo,展示了如何使用retry库:
func ExampleEnsure() {
// 创建一个新的retry实例
r := New()
// 设置超时上下文
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
// 使用Ensure方法执行需要重试的操作
err := r.Ensure(ctx, func() error {
// 第一个HTTP GET请求 - 失败时可重试
resp, err := http.Get("http://www.example.com")
if err != nil {
log.Println(err)
// 使用Retriable标记此错误可重试
return Retriable(err)
}
log.Println(resp)
// 第二个HTTP POST请求 - 失败时不应重试
buf := bytes.NewBuffer(nil)
resp, err = http.Post("http://example.com/upload", "image/jpeg", buf)
if err != nil {
// 直接返回错误,不进行重试
return err
}
log.Println(resp)
return nil
})
if err != nil {
log.Fatal(err)
}
}
代码说明:
- 首先创建一个新的retry实例:
r := New()
- 设置超时上下文,控制整个重试过程的最长时间
- 使用
Ensure
方法执行需要重试的操作,传入一个函数 - 在函数中:
- 对于可重试的操作(如GET请求),使用
Retriable(err)
标记错误 - 对于不应重试的操作(如POST请求),直接返回错误
- 对于可重试的操作(如GET请求),使用
- 最后检查返回的错误,如果有错误则处理
这个库会自动处理重试逻辑,包括:
- 在遇到标记为可重试的错误时自动重试
- 在遇到非可重试错误或成功时停止
- 在上下文超时时停止重试
更多关于golang简单高效的失败重试机制插件库retry的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang简单高效的失败重试机制插件库retry的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 失败重试机制插件库 retry 使用指南
在分布式系统中,失败重试是一个常见需求。Go 生态中有多个优秀的重试库,其中 github.com/avast/retry-go
是一个简单高效的解决方案。下面我将详细介绍其使用方法。
安装
go get github.com/avast/retry-go/v4
基本使用
package main
import (
"errors"
"fmt"
"time"
"github.com/avast/retry-go/v4"
)
func main() {
var count int
err := retry.Do(
func() error {
count++
fmt.Printf("尝试第 %d 次\n", count)
if count < 3 {
return errors.New("模拟失败")
}
return nil // 成功返回nil
},
retry.Attempts(5), // 最多尝试5次
retry.Delay(100*time.Millisecond), // 每次重试间隔100ms
retry.OnRetry(func(n uint, err error) {
fmt.Printf("第 %d 次重试,错误: %v\n", n, err)
}),
)
if err != nil {
fmt.Println("最终失败:", err)
} else {
fmt.Println("最终成功!")
}
}
常用配置选项
retry-go 提供了丰富的配置选项:
err := retry.Do(
func() error { /* ... */ },
retry.Attempts(3), // 最大尝试次数
retry.Delay(100*time.Millisecond), // 基础延迟
retry.MaxDelay(1*time.Second), // 最大延迟
retry.DelayType(retry.BackOffDelay), // 退避策略
retry.LastErrorOnly(true), // 只返回最后一次错误
retry.Context(ctx), // 支持context取消
retry.RetryIf(func(err error) bool { // 自定义重试条件
return err != nil && err != io.EOF
}),
)
实际应用示例
HTTP请求重试
func GetWithRetry(url string) ([]byte, error) {
var body []byte
err := retry.Do(
func() error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 500 {
return fmt.Errorf("服务器错误: %d", resp.StatusCode)
}
body, err = io.ReadAll(resp.Body)
return err
},
retry.Attempts(3),
retry.Delay(1*time.Second),
retry.RetryIf(func(err error) bool {
// 只对网络错误和5xx错误重试
return err != nil || strings.Contains(err.Error(), "服务器错误")
}),
)
return body, err
}
数据库操作重试
func QueryWithRetry(db *sql.DB, query string, args ...interface{}) (*sql.Rows, error) {
var rows *sql.Rows
var err error
retry.Do(
func() error {
rows, err = db.Query(query, args...)
return err
},
retry.Attempts(5),
retry.DelayType(retry.BackOffDelay),
retry.MaxJitter(100*time.Millisecond),
)
return rows, err
}
高级特性
自定义重试策略
func customDelay(n uint, err error, config *retry.Config) time.Duration {
// 指数退避 + 随机抖动
delay := time.Duration(math.Pow(2, float64(n))) * time.Second
jitter := time.Duration(rand.Int63n(int64(delay / 2)))
return delay + jitter
}
err := retry.Do(
func() error { /* ... */ },
retry.DelayType(customDelay),
)
组合多个重试条件
err := retry.Do(
func() error { /* ... */ },
retry.RetryIf(func(err error) bool {
// 网络错误或超时重试
if netErr, ok := err.(net.Error); ok {
return netErr.Timeout() || netErr.Temporary()
}
// 特定业务错误重试
return errors.Is(err, ErrRateLimited) ||
errors.Is(err, ErrServiceUnavailable)
}),
)
注意事项
- 幂等性:确保重试的操作是幂等的,避免重复操作造成数据不一致
- 超时控制:使用
retry.Context(ctx)
配合 context 超时 - 错误处理:区分可重试错误和不可重试错误
- 性能影响:合理设置重试次数和间隔,避免过度重试
retry-go 库简单易用但功能强大,能满足大多数重试场景需求。对于更复杂的场景,还可以考虑 github.com/sethvargo/go-retry
等其他库。