贝利信息

Golang如何实现错误重试机制_Golang函数调用失败重试策略

日期:2026-01-22 00:00 / 作者:php中文网
Go中基础重试应采用指数退避策略,每次失败后休眠时间递增(如100ms→200ms→400ms),并设最大重试次数防无限循环,同时用context.Context控制整体超时。

Go 中用 for + time.Sleep 实现基础重试

最直接的方式是手动循环调用函数,失败后等待再试。关键不是“重试多少次”,而是“等多久再试”——固定间隔容易压垮下游,指数退避更稳妥。

func doWithRetry(ctx context.Context, fn func() error, maxRetries int) error {
    var err error
    delay := 100 * tim

e.Millisecond for i := 0; i <= maxRetries; i++ { select { case <-ctx.Done(): return ctx.Err() default: } err = fn() if err == nil { return nil } if i < maxRetries { time.Sleep(delay) delay *= 2 // 指数退避 } } return err }

backoff.Retry 避免手写退避逻辑

第三方库 github.com/cenkalti/backoff/v4 封装了标准退避策略,比手写更可靠,也支持 jitter(随机抖动)防同步冲击。

import "github.com/cenkalti/backoff/v4"

func callAPIWithBackoff() error { bo := backoff.WithMaxRetries(backoff.NewExponentialBackOff(), 3) bo = backoff.WithJitter(bo, 0.1) // ±10% 抖动 return backoff.Retry(func() error { _, err := http.Get("https://www./link/46b315dd44d174daf5617e22b3ac94ca") return err }, bo) }

重试时绕过 net/http 连接复用陷阱

HTTP 请求失败后直接重试,若底层连接已损坏但 http.Client 仍复用它,会导致后续请求持续失败。必须确保每次重试都用“干净”的请求上下文。

client := &http.Client{
    Transport: &http.Transport{
        IdleConnTimeout: 5 * time.Second,
    },
}

req, _ := http.NewRequest("GET", "https://www./link/46b315dd44d174daf5617e22b3ac94ca", nil) // 每次重试都重新 NewRequest,不复用 req 实例

哪些错误不该重试?

盲目重试会放大问题。HTTP 状态码、gRPC 错误码、数据库约束冲突等,多数属于“永久性失败”,重试无意义甚至有害。

网络超时、连接拒绝、5xx 服务端错误、临时限流响应(如 429 Too Many RequestsRetry-After)才适合重试。