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),
)

最佳实践

  1. 合理设置重试次数:避免无限重试导致系统雪崩
  2. 使用指数退避:减轻服务压力
  3. 记录重试日志:便于问题排查
  4. 区分可重试错误:不是所有错误都适合重试
  5. 结合熔断机制:防止重试风暴

Repeat 库通过简单的 API 提供了强大的重试能力,结合 Go 的并发特性,可以轻松实现各种健壮性要求高的分布式系统组件。

回到顶部