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

代码说明:

  1. 首先创建一个新的retry实例:r := New()
  2. 设置超时上下文,控制整个重试过程的最长时间
  3. 使用Ensure方法执行需要重试的操作,传入一个函数
  4. 在函数中:
    • 对于可重试的操作(如GET请求),使用Retriable(err)标记错误
    • 对于不应重试的操作(如POST请求),直接返回错误
  5. 最后检查返回的错误,如果有错误则处理

这个库会自动处理重试逻辑,包括:

  • 在遇到标记为可重试的错误时自动重试
  • 在遇到非可重试错误或成功时停止
  • 在上下文超时时停止重试

更多关于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)
    }),
)

注意事项

  1. 幂等性:确保重试的操作是幂等的,避免重复操作造成数据不一致
  2. 超时控制:使用 retry.Context(ctx) 配合 context 超时
  3. 错误处理:区分可重试错误和不可重试错误
  4. 性能影响:合理设置重试次数和间隔,避免过度重试

retry-go 库简单易用但功能强大,能满足大多数重试场景需求。对于更复杂的场景,还可以考虑 github.com/sethvargo/go-retry 等其他库。

回到顶部