pkg/retry 提供简单的重试机制,支持多种重试策略。
| 策略 | 说明 |
|---|---|
StrategyFixed | 固定延迟,每次重试间隔相同 |
StrategyLinear | 线性递增延迟,每次重试延迟增加 |
StrategyExponential | 指数退避延迟,每次重试延迟翻倍 |
type Config struct {
MaxAttempts int // 最大重试次数
InitialDelay time.Duration // 初始延迟
MaxDelay time.Duration // 最大延迟
Strategy Strategy // 重试策略
OnRetry func(attempt int, err error) // 重试回调
}
err := retry.Do(fn func() error, config Config) error
MaxAttempts:最大重试次数,包括第一次尝试InitialDelay:第一次重试前的延迟时间MaxDelay:最大延迟上限,避免延迟过长Strategy:重试策略OnRetry:每次重试前调用的回调函数| 策略 | 第 N 次重试延迟 |
|---|---|
StrategyFixed | InitialDelay |
StrategyLinear | N × InitialDelay |
StrategyExponential | 2^(N-1) × InitialDelay |
package main
import (
"fmt"
"net/http"
"time"
"github.com/darkit/gin/pkg/retry"
)
func main() {
err := retry.Do(
func() error {
resp, err := http.Get("https://api.example.com/health")
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unexpected status: %d", resp.StatusCode)
}
return nil
},
retry.Config{
MaxAttempts: 3,
InitialDelay: 100 * time.Millisecond,
MaxDelay: time.Second,
Strategy: retry.StrategyFixed,
},
)
if err != nil {
fmt.Println("All retries failed:", err)
} else {
fmt.Println("Request succeeded")
}
}
err := retry.Do(
fn,
retry.Config{
MaxAttempts: 5,
InitialDelay: 100 * time.Millisecond,
MaxDelay: 30 * time.Second,
Strategy: retry.StrategyExponential,
},
)
err := retry.Do(
fn,
retry.Config{
MaxAttempts: 3,
InitialDelay: 200 * time.Millisecond,
Strategy: retry.StrategyExponential,
OnRetry: func(attempt int, err error) {
fmt.Printf("Retry %d: %v\n", attempt, err)
metrics.Inc("retry_attempt")
},
},
)
func fetchUser(userID string) (*User, error) {
var user *User
err := retry.Do(
func() error {
return db.Where("id = ?", userID).First(&user).Error
},
retry.Config{
MaxAttempts: 3,
InitialDelay: 50 * time.Millisecond,
Strategy: retry.StrategyLinear,
},
)
return user, err
}
func callAPIWithRetry(url string) ([]byte, error) {
var result []byte
err := retry.Do(
func() error {
resp, err := httpClient.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode >= 500 {
return fmt.Errorf("server error: %d", resp.StatusCode)
}
if resp.StatusCode == 429 { // Too Many Requests
return ErrRateLimited
}
result, err = io.ReadAll(resp.Body)
return err
},
retry.Config{
MaxAttempts: 5,
InitialDelay: time.Second,
MaxDelay: 60 * time.Second,
Strategy: retry.StrategyExponential,
},
)
return result, err
}
最大重试次数:
初始延迟:
最大延迟:
策略选择:
StrategyFixed:适用于偶发性失败StrategyLinear:适用于负载均衡场景StrategyExponential:适用于服务暂时不可用场景幂等性: