golang实现多种重试策略和心跳检测的插件库repeat的使用
Golang实现多种重试策略和心跳检测的插件库repeat的使用
Repeat是一个Go语言实现的库,提供了多种回退策略,可用于重试操作和心跳检测。
示例
回退策略(Backoff)
假设我们需要在远程服务器上进行REST调用,但可能会因各种问题失败。我们可以使用指数回退策略重试失败的操作。
// 示例操作,前5次会失败
var last time.Time
op := func(c int) error {
printInfo(c, &last)
if c < 5 {
return repeat.HintTemporary(errors.New("can't connect to a server"))
}
return nil
}
// 在任何错误时重试操作,最多10次,使用回退策略
err := repeat.Repeat(
// 带计数器的操作函数
repeat.FnWithCounter(op),
// 如果操作返回nil则停止重试
repeat.StopOnSuccess(),
// 最多10次重试
repeat.LimitMaxTries(10),
// 使用带完整抖动的回退延迟
repeat.WithDelay(
repeat.FullJitterBackoff(500*time.Millisecond).Set(),
),
)
输出示例:
Attempt #0, Delay 0s
Attempt #1, Delay 373.617912ms
Attempt #2, Delay 668.004225ms
Attempt #3, Delay 1.220076558s
Attempt #4, Delay 2.716156336s
Attempt #5, Delay 6.458431017s
Repetition process is finished with: <nil>
带超时的回退策略
下面的示例与上一个几乎相同,但增加了一个重要特性 - 可以使用上下文超时取消操作重试。
// 带取消功能的上下文,3秒后取消重试
ctx, cancelFunc := context.WithCancel(context.Background())
go func() {
time.Sleep(3 * time.Second)
cancelFunc()
}()
// 在任何错误时重试操作,最多10次,使用回退策略
err := repeat.Repeat(
...
// 使用带完整抖动的回退延迟和上下文
repeat.WithDelay(
repeat.FullJitterBackoff(500*time.Millisecond).Set(),
repeat.SetContext(ctx),
),
...
)
输出示例:
Attempt #0, Delay 0s
Attempt #1, Delay 358.728046ms
Attempt #2, Delay 845.361787ms
Attempt #3, Delay 61.527485ms
Repetition process is finished with: context canceled
心跳检测(Heartbeating)
假设我们需要定期向远程服务器报告执行进度。下面的示例每秒重复一次操作,直到通过传递的上下文取消。
// 心跳检测示例操作
var last time.Time
op := func(c int) error {
printInfo(c, &last)
return nil
}
// 带取消功能的上下文,7秒后取消
ctx, cancelFunc := context.WithCancel(context.Background())
go func() {
time.Sleep(7 * time.Second)
cancelFunc()
}()
err := repeat.Repeat(
// 心跳检测操作
repeat.FnWithCounter(op),
// 使用固定回退延迟和上下文
repeat.WithDelay(
repeat.FixedBackoff(time.Second).Set(),
repeat.SetContext(ctx),
),
)
输出示例:
Attempt #0, Delay 0s
Attempt #1, Delay 1.001129426s
Attempt #2, Delay 1.000155727s
Attempt #3, Delay 1.001131014s
Attempt #4, Delay 1.000500428s
Attempt #5, Delay 1.0008985s
Attempt #6, Delay 1.000417057s
Repetition process is finished with: context canceled
带错误超时的心跳检测
下面的示例与上一个几乎相同,但会使用特殊的错误超时来取消。每次操作返回nil时,这个超时都会重置。
// 心跳检测示例操作,3次成功尝试后失败5次
var last time.Time
op := func(c int) error {
printInfo(c, &last)
if c > 3 && c < 8 {
return repeat.HintTemporary(errors.New("can't connect to a server"))
}
return nil
}
err := repeat.Repeat(
// 心跳检测操作
repeat.FnWithCounter(op),
// 使用固定回退延迟和错误超时
repeat.WithDelay(
repeat.FixedBackoff(time.Second).Set(),
repeat.SetErrorsTimeout(3*time.Second),
),
)
输出示例:
Attempt #0, Delay 0s
Attempt #1, Delay 1.001634616s
Attempt #2, Delay 1.004912408s
Attempt #3, Delay 1.001021358s
Attempt #4, Delay 1.001249459s
Attempt #5, Delay 1.004320833s
Repetition process is finished with: can't connect to a server
更多关于golang实现多种重试策略和心跳检测的插件库repeat的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
1 回复
更多关于golang实现多种重试策略和心跳检测的插件库repeat的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Golang 重试与心跳检测库 Repeat 使用指南
Repeat 是一个 Go 语言实现的轻量级库,提供了多种重试策略和心跳检测功能,非常适合处理网络请求、服务调用等需要容错机制的场景。
安装
go get github.com/avast/retry-go
基本重试功能
简单重试示例
package main
import (
"fmt"
"time"
"github.com/avast/retry-go"
)
func main() {
err := retry.Do(
func() error {
// 模拟可能失败的操作
if time.Now().Second()%2 != 0 {
return fmt.Errorf("something went wrong")
}
return nil
},
retry.Attempts(3),
retry.Delay(100*time.Millisecond),
)
if err != nil {
fmt.Println("最终失败:", err)
} else {
fmt.Println("操作成功!")
}
}
多种重试策略
1. 固定间隔重试
err := retry.Do(
operation,
retry.Attempts(5),
retry.Delay(1*time.Second),
)
2. 指数退避重试
err := retry.Do(
operation,
retry.Attempts(5),
retry.DelayType(retry.BackOffDelay),
retry.MaxDelay(10*time.Second),
)
3. 随机间隔重试
err := retry.Do(
operation,
retry.Attempts(5),
retry.DelayType(retry.RandomDelay),
retry.MaxJitter(2*time.Second),
)
4. 自定义重试条件
err := retry.Do(
operation,
retry.RetryIf(func(err error) bool {
// 只对特定错误重试
return err == io.EOF
}),
)
心跳检测实现
虽然 retry-go 主要关注重试,但我们可以结合它实现心跳检测:
package main
import (
"context"
"fmt"
"time"
"github.com/avast/retry-go"
)
func heartbeat(ctx context.Context) {
ticker := time.NewTicker(1 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
err := retry.Do(
func() error {
// 执行心跳检测
return checkServiceHealth()
},
retry.Attempts(3),
retry.Delay(100*time.Millisecond),
)
if err != nil {
fmt.Println("服务不可用:", err)
// 触发告警或恢复逻辑
} else {
fmt.Println("心跳正常")
}
}
}
}
func checkServiceHealth() error {
// 实现实际的心跳检测逻辑
if time.Now().Second()%10 == 0 {
return fmt.Errorf("模拟服务故障")
}
return nil
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
go heartbeat(ctx)
// 主程序运行10分钟后退出
time.Sleep(10 * time.Minute)
}
高级功能
重试中间件
func withRetry(fn func() error) error {
return retry.Do(
fn,
retry.Attempts(3),
retry.OnRetry(func(n uint, err error) {
fmt.Printf("第%d次重试,错误: %v\n", n, err)
}),
)
}
上下文支持
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
err := retry.Do(
func() error {
return operationWithContext(ctx)
},
retry.Context(ctx),
)
最佳实践
- 合理设置重试次数:避免无限重试导致系统雪崩
- 使用指数退避:减轻服务压力
- 记录重试日志:便于问题排查
- 区分可重试错误:不是所有错误都适合重试
- 结合熔断机制:防止重试风暴
Repeat 库通过简单的 API 提供了强大的重试能力,结合 Go 的并发特性,可以轻松实现各种健壮性要求高的分布式系统组件。