retry

package
v0.0.16 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 28, 2026 License: MIT Imports: 5 Imported by: 0

README

retry

简介

retry 包提供了通用的重试机制,支持带上下文和不带上下文的函数重试,内置指数退避(Backoff)和可选抖动(Jitter)机制,适用于网络请求、数据库操作等易失败场景。通过灵活的配置选项,开发者可自定义重试策略,提升系统健壮性。

主要特性
  • 支持无上下文和带上下文的函数重试
  • 内置指数退避与抖动机制,减少并发冲突
  • 灵活的最小/最大等待时间、增长因子等参数配置
  • 支持重试过程的取消与超时控制
  • API 简洁,易于集成
  • 完整的单元测试覆盖
设计理念

本包设计注重通用性与灵活性,采用函数式选项模式(Functional Options)配置重试策略,便于扩展和组合。通过与 Go 的 context 包深度集成,支持优雅的取消和超时控制,适合高并发和分布式系统。

安装

前置条件
  • Go 版本要求:Go 1.18 或更高版本
  • 依赖要求:
    • 仅依赖 Go 标准库
安装命令
go get -u github.com/fsyyft-go/kit/runtime/retry

快速开始

基础用法
package main

import (
    "fmt"
    "github.com/fsyyft-go/kit/runtime/retry"
)

func main() {
    // 定义一个可能失败的操作
    count := 0
    err := retry.Retry(func() error {
        count++
        if count < 3 {
            return fmt.Errorf("第 %d 次失败", count)
        }
        return nil
    })
    if err != nil {
        fmt.Printf("重试失败: %v\n", err)
    } else {
        fmt.Println("重试成功")
    }
}
带上下文的用法
package main

import (
    "context"
    "fmt"
    "time"
    "github.com/fsyyft-go/kit/runtime/retry"
)

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Second)
    defer cancel()
    count := 0
    err := retry.RetryWithContext(ctx, func(ctx context.Context) error {
        count++
        if count < 5 {
            return fmt.Errorf("第 %d 次失败", count)
        }
        return nil
    }, retry.WithMin(10*time.Millisecond), retry.WithMax(50*time.Millisecond))
    if err != nil {
        fmt.Printf("重试失败: %v\n", err)
    } else {
        fmt.Println("重试成功")
    }
}
配置选项
// 可通过函数式选项自定义重试策略:
retry.Retry(fn,
    retry.WithMin(100*time.Millisecond), // 最小等待时间
    retry.WithMax(2*time.Second),        // 最大等待时间
    retry.WithFactor(1.5),               // 增长因子
    retry.WithJitter(true),              // 启用抖动
)

详细指南

核心概念
重试机制

重试机制用于在操作失败时自动重新尝试,常用于网络、IO、数据库等易受外部影响的场景。合理的重试策略可显著提升系统的健壮性和可用性。

指数退避(Exponential Backoff)

每次重试等待时间按指数递增,有效避免雪崩和资源竞争。可通过 WithFactorWithMinWithMax 配置增长速率和区间。

抖动(Jitter)

抖动机制在退避基础上引入随机性,减少高并发场景下的同步重试冲突。通过 WithJitter(true) 启用。

常见用例
1. 网络请求重试
err := retry.Retry(func() error {
    // 执行网络请求
    return doRequest()
}, retry.WithJitter(true))
2. 数据库操作重试
err := retry.RetryWithContext(ctx, func(ctx context.Context) error {
    // 执行数据库操作
    return db.ExecContext(ctx, sql)
}, retry.WithMin(50*time.Millisecond), retry.WithMax(500*time.Millisecond))
最佳实践
  • 合理设置最大重试次数,避免无限重试
  • 使用带 context 的重试,支持取消和超时
  • 在高并发场景下建议开启抖动
  • 根据业务场景调整退避参数,平衡重试速度与系统压力
  • 对于不可恢复的错误应及时中断重试

API 文档

主要类型
// RetryableFunc 定义了可重试的函数类型。
type RetryableFunc func() error

// RetryableFuncWithContext 定义了带上下文的可重试函数类型。
type RetryableFuncWithContext func(ctx context.Context) error

// Backoff 退避策略生成器,支持参数化配置。
type Backoff struct {
    // ...字段详见源码...
}
关键函数
Retry

对无 context 的函数进行重试。

func Retry(fn RetryableFunc, opts ...BackoffOption) error
RetryWithContext

对带 context 的函数进行重试,支持取消和超时。

func RetryWithContext(ctx context.Context, fn RetryableFuncWithContext, opts ...BackoffOption) error
Backoff 相关
  • NewBackoff(opts ...BackoffOption) *Backoff:创建退避策略实例
  • WithMin(min time.Duration) BackoffOption:设置最小等待时间
  • WithMax(max time.Duration) BackoffOption:设置最大等待时间
  • WithFactor(factor float64) BackoffOption:设置增长因子
  • WithJitter(jitter bool) BackoffOption:启用/禁用抖动
错误处理
  • 当所有重试均失败时,返回最后一次的错误
  • 若 context 被取消或超时,返回 context 的错误

性能指标

操作 性能指标 说明
单次重试 ~100ns 仅退避计算
带抖动重试 ~150ns 包含随机数生成
并发重试 ~200ns/协程 退避计算并发安全

测试覆盖率

覆盖率
retry >95%

调试指南

常见问题排查
重试未生效
  • 检查重试函数返回值,确保失败时返回 error
  • 检查 context 是否提前取消或超时
  • 检查退避参数设置是否合理
性能问题
  • 合理设置最小/最大等待时间,避免频繁重试
  • 并发场景下建议使用 ForAttempt 方法

相关文档

Documentation

Overview

Package retry 提供基于 Backoff 的重试等待计算和重试循环。

本包既支持直接重试 func() error,也支持由 context.Context 控制取消和超时的重试。 Backoff 使用最小值、最大值、增长因子和可选抖动计算每次等待时间,适合需要指数退避的失败重试场景。

Retry 和 RetryWithContext 在被调函数返回普通错误时不会直接结束;它们会继续等待下一次重试, 直到函数成功返回 nil,或上下文被取消后返回 ctx.Err()。如果调用方需要限制总时长、总次数 或区分可重试与不可重试错误,需要自行通过 context 或包装逻辑实现。

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Retry

func Retry(fn RetryableFunc, opts ...BackoffOption) error

Retry 使用 context.Background 按退避策略反复执行 fn,直到 fn 返回 nil。

当 fn 返回普通错误时,Retry 不会提前返回该错误,而是继续等待下一次重试。 由于本函数内部固定使用 context.Background,调用方不能直接取消本次重试循环; 如果 fn 始终失败且没有其他外部中断条件,本函数可能永不返回。传入 nil fn 会在首次调用时 panic。

参数:

  • fn: 待执行的可重试函数;返回非 nil error 时会继续重试。
  • opts: Backoff 配置选项,按传入顺序应用。

返回:

  • error: fn 成功时返回 nil;普通业务错误不会被直接返回。

func RetryWithContext

func RetryWithContext(ctx context.Context, fn RetryableFuncWithContext, opts ...BackoffOption) error

RetryWithContext 按退避策略反复执行 fn,直到 fn 返回 nil 或 ctx 被取消。

普通业务错误会触发下一次重试,不会被直接返回。ctx.Done() 在调用前或等待期间触发时, RetryWithContext 返回 ctx.Err()。传入 nil ctx 或 nil fn 会在首次使用时 panic。

参数:

  • ctx: 用于取消或超时控制的上下文;取消或超时后会终止后续重试等待。
  • fn: 待执行的可重试函数。fn 应尊重 ctx.Done() 并尽快返回;返回非 nil error 时会继续重试。
  • opts: Backoff 配置选项,按传入顺序应用。

返回:

  • error: fn 成功时返回 nil;ctx 取消或超时时返回 ctx.Err()。

Types

type Backoff

type Backoff struct {
	// contains filtered or unexported fields
}

Backoff 根据尝试次数计算退避等待时间。

零值 Backoff 在计算时会回退到默认最小值、最大值和增长因子。Backoff 在创建完成后可被多个 goroutine 共享使用;Backoff.DurationBackoff.ResetBackoff.Attempt 通过原子操作维护 内部 attempt 计数,而 Backoff.ForAttempt 只按显式给定的尝试次数计算等待时间。Backoff 的方法要求 接收者非 nil。

func NewBackoff

func NewBackoff(opts ...BackoffOption) *Backoff

NewBackoff 创建一个新的 Backoff 实例。

默认配置为:min 100ms、max 10s、factor 2、jitter false。多个选项按传入顺序依次应用, 同一字段以后传入的值为准。返回的实例初始 attempt 计数为 0。

参数:

  • opts: 可选的 Backoff 配置项;nil 选项函数会在应用阶段触发 panic。

返回:

  • *Backoff: 应用全部选项后的退避配置实例。

func (*Backoff) Attempt

func (b *Backoff) Attempt() float64

Attempt 返回当前内部 attempt 计数。

返回值使用 float64,以便直接作为 Backoff.ForAttempt 的参数复用。

参数:无。

返回:

  • float64: 当前内部 attempt 计数。

func (*Backoff) Copy

func (b *Backoff) Copy() *Backoff

Copy 返回一个参数配置与当前实例一致的新 Backoff

新实例不会复制当前的 attempt 计数,返回后的第一次 Backoff.Duration 调用会从第 0 次尝试重新开始。

参数:无。

返回:

  • *Backoff: 与当前实例配置一致、但 attempt 计数重置为 0 的新实例。

func (*Backoff) Duration

func (b *Backoff) Duration() time.Duration

Duration 返回当前 attempt 对应的等待时间,并将 attempt 加 1。

多个 goroutine 并发调用 Duration 时会共享同一 attempt 序列,返回顺序取决于竞争结果; 需要按指定尝试次数独立计算等待时间时,请使用 Backoff.ForAttempt

参数:无。

返回:

  • time.Duration: 当前 attempt 对应的退避等待时间。

func (*Backoff) ForAttempt

func (b *Backoff) ForAttempt(attempt float64) time.Duration

ForAttempt 根据指定的尝试次数计算等待时间。

当 min、max 或 factor 为非正值时,本方法会回退到默认配置;当 min 大于等于 max 时, 直接返回 max。启用 jitter 后,结果会在最小值和理论退避值之间随机取值,再按 max 截断。

参数:

  • attempt: 目标尝试次数,从 0 开始;第 0 次尝试的理论等待时间为 min。

返回:

  • time.Duration: 指定尝试次数对应的退避等待时间。

func (*Backoff) Reset

func (b *Backoff) Reset()

Reset 将内部 attempt 计数重置为 0。

调用后,下一次 Backoff.Duration 会重新按第 0 次尝试计算等待时间。

参数:无。

type BackoffOption

type BackoffOption func(*Backoff)

BackoffOption 配置 Backoff 的等待参数。

多个选项按传入顺序依次应用;同一字段以后传入的值为准。

参数:

func WithFactor

func WithFactor(factor float64) BackoffOption

WithFactor 设置 Backoff 的增长因子。

factor 小于等于 0 时不会在构造阶段报错;实际计算等待时间时会回退到默认增长因子。

参数:

  • factor: 期望设置的退避增长因子。

返回:

  • BackoffOption: 写入增长因子配置的选项函数。

func WithJitter

func WithJitter(jitter bool) BackoffOption

WithJitter 设置 Backoff 是否在退避结果中加入抖动。

启用后,Backoff.ForAttempt 会在最小值和理论退避值之间取随机值,再按最大值上限截断。

参数:

  • jitter: 是否启用抖动。

返回:

  • BackoffOption: 写入抖动配置的选项函数。

func WithMax

func WithMax(max time.Duration) BackoffOption

WithMax 设置 Backoff 的最大等待时间。

max 小于等于 0 时不会在构造阶段报错;实际计算等待时间时会回退到默认最大值。

参数:

  • max: 期望设置的最大等待时间。

返回:

  • BackoffOption: 写入最大等待时间配置的选项函数。

func WithMin

func WithMin(min time.Duration) BackoffOption

WithMin 设置 Backoff 的最小等待时间。

min 小于等于 0 时不会在构造阶段报错;实际计算等待时间时会回退到默认最小值。

参数:

  • min: 期望设置的最小等待时间。

返回:

  • BackoffOption: 写入最小等待时间配置的选项函数。

type RetryableFunc

type RetryableFunc func() error

RetryableFunc 表示不接收 context 的可重试函数。

返回 nil 时结束重试;返回非 nil error 时,Retry 会把该错误视为一次可重试失败并继续等待下一次调用。

参数:无。

返回:

  • error: 返回 nil 时停止重试;返回非 nil 时由 Retry 继续按退避策略重试,不会被直接返回给调用方。

type RetryableFuncWithContext

type RetryableFuncWithContext func(ctx context.Context) error

RetryableFuncWithContext 表示接收 context 的可重试函数。

实现应尊重 ctx.Done() 并在不再继续工作时尽快返回。返回 nil 时结束重试;返回非 nil error 时, RetryWithContext 会把该错误视为一次可重试失败并继续等待下一次调用。

参数:

  • ctx: 当前重试调用使用的上下文;实现应监听其取消信号并尽快终止不再需要的工作。

返回:

  • error: 返回 nil 时停止重试;返回非 nil 时由 RetryWithContext 继续按退避策略重试,不会被直接返回给调用方。

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL