cenkalti/backoff

GitHub: cenkalti/backoff

一个 Go 语言的指数退避重试库,为失败操作提供指数递增间隔的自动重试能力。

Stars: 4038 | Forks: 218

# 指数退避 [![GoDoc](https://pkg.go.dev/badge/github.com/cenkalti/backoff/v7.svg)][godoc] 这是从 [Google 的 Java HTTP 客户端库][google-http-java-client] 移植到 Go 的指数退避算法。 [指数退避][exponential backoff wiki] 是一种算法,它使用反馈来成倍地降低某个过程的速率, 以便逐渐找到可接受的速率。 重试次数会呈指数级增加,并在达到某个阈值时停止增加。 ## 安装 ``` go get github.com/cenkalti/backoff/v7 ``` 请注意导入路径末尾的 `/v7`。 ## 用法 在大多数情况下,将你想要重试的操作包装在 `Retry` 中: ``` result, err := backoff.Retry(ctx, func() (string, error) { resp, err := http.Get("https://www.example.com") if err != nil { return "", err // transient: Retry will try again } defer resp.Body.Close() switch { case resp.StatusCode >= 500: return "", fmt.Errorf("server error: %s", resp.Status) // retried case resp.StatusCode >= 400: // client errors won't fix themselves, so stop retrying. return "", backoff.Permanent(fmt.Errorf("client error: %s", resp.Status)) } return "ok", nil }, backoff.WithMaxTries(5)) ``` `Retry` 至少运行一次操作,并使用指数 退避不断重试,直到成功、返回 `Permanent` 错误或达到限制。 有关更完整的示例,请参阅 [example_test.go][example],有关可用选项(`WithBackOff`、`WithMaxTries`、`WithMaxElapsedTime`、 `WithNotify`),请参阅[包文档][godoc]。 如果 `Retry` 不符合你的需求,可以从 [retry.go][retry-src] 中复制它并进行修改。 ### 处理错误 失败时,`Retry` 总是返回一个 `*RetryError`。它携带了最后一次操作的错误(`LastErr`)以及停止重试的原因(`Cause`)。使用 `errors.Is` 检查它,或者使用 `AsRetryError` 获取该结构体: ``` result, err := backoff.Retry(ctx, operation) switch { case errors.Is(err, backoff.ErrPermanent): // the operation returned a Permanent error case errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded): // the caller's context was cancelled or its deadline expired case errors.Is(err, backoff.ErrMaxElapsedTime): // the WithMaxElapsedTime budget was exhausted case errors.Is(err, backoff.ErrExhausted): // WithMaxTries was reached or the backoff policy returned Stop } // The last operation error is always available, whatever the cause: if re := backoff.AsRetryError(err); re != nil { log.Printf("gave up after last error: %v", re.LastErr) } ``` 使用 `backoff.Permanent(err)` 将错误标记为不可重试;`Retry` 会立即停止并返回一个 `*RetryError`,其 `Cause` 为 `ErrPermanent`,`LastErr` 为 `err`。 ### 限制总时间 两个独立的限制控制着 `Retry` 的运行时长,并且它们的行为有所不同: - **context deadline** (`context.WithTimeout`) 是响应式的:它会中断尝试之间的等待,并且——如果你的操作观察了 context——可以中止正在进行的尝试。`Retry` 将其报告为 `context.DeadlineExceeded`。 - **`WithMaxElapsedTime`** 仅限制重试调度:它在尝试之间进行检查,从不中断正在运行的操作,并被报告为 `ErrMaxElapsedTime`。 `WithMaxElapsedTime` 默认为 15 分钟,因此**除非你覆盖它,否则这两个限制都会生效** —— 传入 `backoff.WithMaxElapsedTime(0)` 以完全依赖 context。 ## 贡献 * 我想让这个库尽可能小。 * 请不要在没有开启 issue 并首先讨论的情况下发送 PR。 * 如果提议的更改不是一个常见的用例,我可能不会接受它。
标签:EVTX分析, Go, Ruby工具, 容错处理, 开发库, 指数退避, 日志审计, 网络请求, 重试机制