Skip to content

🔄 重试与限流

网络不稳?限流触发?本库内置重试,并提供可插拔限流。

自动重试

doRequest网络错误5xx 服务端错误自动重试:

go
for i := 0; i <= c.Retries; i++ {
	resp, err = c.HTTPClient.Do(req)
	if err == nil && resp.StatusCode < 500 {
		break  // 成功
	}
	// ... 关闭 body,等待,重试
	time.Sleep(defaultRetryDelay) // 500ms
}
  • 🔄 默认重试 2 次(共 3 次请求)
  • ⏱ 固定退避 500msdefaultRetryDelay
  • 🚫 只重试网络错误与 5xx,重试 4xx(客户端错误不可恢复)

配置重试次数

go
client := ipapi.NewClient()
client.Retries = 5 // 改成 5 次

💡 直接改字段

Retries 是导出字段,创建后直接赋值即可。也可在 NewClient 后调整。

设为 0 则不重试:

go
client.Retries = 0

速率限制 RateLimiter

Client.RateLimiter<-chan time.Time。非空时,每次请求前阻塞等待令牌:

go
// 每秒最多 1 次请求
client := ipapi.NewClient()
client.RateLimiter = time.Tick(time.Second)

为什么用通道

  • 🧵 天然并发安全,多 goroutine 自动排队
  • 🔌 可插拔:塞任意 <-chan time.Time
  • 🪶 比锁/接口轻量

自定义限流策略

time.Tick 是固定速率。要做令牌桶、动态调速,自己造 channel 即可:

go
// 漏桶:每 200ms 放一个令牌 = 5 QPS
client.RateLimiter = time.Tick(200 * time.Millisecond)

// 突发+恢复:缓冲通道
bucket := make(chan time.Time, 10) // 突发 10
go func() {
	for range time.Tick(time.Second) {
		select {
		case bucket <- time.Now():
		default:
		}
	}
}()
client.RateLimiter = bucket

限流错误处理

触发服务端限流(HTTP 429)会返回 ErrRateLimited

go
if errors.Is(err, ipapi.ErrRateLimited) {
	time.Sleep(time.Minute) // 业务层退避
}

重试 + 限流协同

🎨 一图抵千言

下图展示一次 GetIPInfo 调用的完整时序:限流器先放行令牌,doRequest 进入重试循环,遇到网络错误或 5xx 时退避 500ms 后重试,4xx 则立即终止。

下面是等价的文字版流程,便于复制粘贴:

请求 → RateLimiter 阻塞拿令牌 → 发请求 → 成功?
                                          │ No
                                          ├─ 网络错误/5xx → sleep 500ms → 重试
                                          └─ 4xx → 立即返回错误

重试循环展开时序

下图聚焦 for i := 0; i <= c.Retries; i++ 循环内部,逐轮展开网络错误/5xx 重试与 4xx 立即终止的对照:

可重试错误判断

业务层判断是否值得重试,用 IsRetryableError

go
for attempt := 0; attempt < 3; attempt++ {
	info, err := client.GetIPInfo(ctx, ip, "json")
	if err == nil {
		break
	}
	if !ipapi.IsRetryableError(err) {
		break // 不可重试,放弃
	}
	time.Sleep(time.Duration(1<<attempt) * time.Second) // 指数退避
}

哨兵错误重试分类

下图用状态图展示 IsRetryableError 的判定视角:错误被归入「可重试」或「不可重试」终态,业务层据此决定是否继续。

配额规划建议

流量级建议配置
偶发默认
中等RateLimiter = time.Tick
高并发令牌桶 + Retries 适当降低
生产申请付费 Key 提升配额

下一步

基于 MIT 许可证发布