Skip to content

Commit 2407e38

Browse files
authored
Merge pull request #4 from wangkechun/wkc/next
MaxRetryCapacity
2 parents 7eed197 + 97f779f commit 2407e38

File tree

2 files changed

+80
-6
lines changed

2 files changed

+80
-6
lines changed

retry.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,19 @@ type retryableFuncResp struct {
2323
}
2424

2525
type Config struct {
26-
FastRetryTime time.Duration // 默认 2s,建议设置成当前 API 的 PCT99
27-
MaxRetryRate float64 // 最大重试百分比,0.05 代表 5%,默认 5%,超出返回 ErrRetryQuotaExceeded
28-
RetryCnt int // 最多发送的请求次数,默认 3 次,最少两次,其中一次是快速重试
29-
RetryWaitTime time.Duration // 重试间隔,默认是 FastRetryTime / 10
30-
Clock Clock // 模拟时钟,mock 用
26+
FastRetryTime time.Duration // 默认 2s,建议设置成当前 API 的 PCT99
27+
MaxRetryRate float64 // 最大重试百分比,0.05 代表 5%,默认 5%,超出返回 ErrRetryQuotaExceeded
28+
RetryCnt int // 最多发送的请求次数,默认 3 次,最少两次,其中一次是快速重试
29+
RetryWaitTime time.Duration // 重试间隔,默认是 FastRetryTime / 10
30+
Clock Clock // 模拟时钟,mock 用
31+
MaxRetryCapacity int // 平时没有超时的时候,允许积攒的重启请求最大数目,默认 1000 个
3132
}
3233

3334
type Retry struct {
3435
cfg *Config
3536
score atomic.Int64
3637
oneRetryScore int64
38+
maxScore int64
3739
}
3840

3941
func New(config Config) *Retry {
@@ -60,13 +62,19 @@ func New(config Config) *Retry {
6062
panic("bad MaxRetryRate")
6163
}
6264
r.oneRetryScore = int64(1 / r.cfg.MaxRetryRate)
65+
if r.cfg.MaxRetryCapacity == 0 {
66+
r.cfg.MaxRetryCapacity = 1000
67+
}
68+
r.maxScore = int64(r.cfg.MaxRetryCapacity) * r.oneRetryScore
6369
return r
6470
}
6571

6672
func (r *Retry) BackupRetry(ctx context.Context, retryableFunc func() (resp interface{}, err error)) (resp interface{}, err error) {
6773
ctx, cancel := context.WithCancel(ctx)
6874
defer cancel()
69-
r.score.Add(1)
75+
if r.score.Load() < r.maxScore {
76+
r.score.Add(1)
77+
}
7078
doFunc := func() retryableFuncResp {
7179
resp, err := retryableFunc()
7280
return retryableFuncResp{resp: resp, err: err}

retry_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package fast_retry
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
"log"
78
"math/rand"
89
"os"
@@ -188,6 +189,71 @@ func TestMaxRetryRate(t *testing.T) {
188189
require.True(t, callbackCnt.Load() < int64(float64(successCnt.Load())*1.2))
189190
}
190191

192+
func TestMaxRetryCapacity(t *testing.T) {
193+
if testing.Short() {
194+
t.Skip()
195+
}
196+
ctx := context.Background()
197+
var callbackCnt atomic.Int64
198+
var errorCnt atomic.Int64
199+
var successCnt atomic.Int64
200+
// 模拟 FastRetryTime 设置不当,看请求是否放大两次
201+
maxRetryCapacity := 100
202+
r := New(Config{MaxRetryRate: 0.1, FastRetryTime: time.Second / 15, MaxRetryCapacity: maxRetryCapacity})
203+
slow := false
204+
fn := func() (resp interface{}, err error) {
205+
callbackCnt.Inc()
206+
if slow {
207+
time.Sleep(time.Second / 10)
208+
}
209+
return "ok", nil
210+
}
211+
{
212+
g, ctx := errgroup.WithContext(ctx)
213+
for i := 0; i < 100; i++ {
214+
g.Go(func() error {
215+
for j := 0; j < 100; j++ {
216+
_, err := r.BackupRetry(ctx, fn)
217+
if err != nil {
218+
fmt.Println(err)
219+
errorCnt.Inc()
220+
} else {
221+
successCnt.Inc()
222+
}
223+
}
224+
return nil
225+
})
226+
}
227+
_ = g.Wait()
228+
}
229+
230+
slow = true
231+
{
232+
g, ctx := errgroup.WithContext(ctx)
233+
for i := 0; i < 50; i++ {
234+
g.Go(func() error {
235+
for j := 0; j < 100; j++ {
236+
_, err := r.BackupRetry(ctx, fn)
237+
if err != nil {
238+
fmt.Println(err)
239+
errorCnt.Inc()
240+
} else {
241+
successCnt.Inc()
242+
}
243+
}
244+
return nil
245+
})
246+
}
247+
_ = g.Wait()
248+
}
249+
// 先 10000 个快速请求,然后 5000 个慢请求
250+
// 5000 里面会有 10% 被重试,之前 10000 会积累一部分 quota
251+
t.Logf("%v %v %v", callbackCnt.Load(), errorCnt.Load(), successCnt.Load())
252+
require.Equal(t, errorCnt.Load(), int64(0))
253+
require.True(t, callbackCnt.Load() < int64(float64(successCnt.Load())*1.2))
254+
require.True(t, callbackCnt.Load() <= int64(10000+5000+5000*0.1+maxRetryCapacity*2))
255+
}
256+
191257
func BenchmarkRetry(b *testing.B) {
192258
ctx := context.Background()
193259
r := New(Config{MaxRetryRate: 0.1, FastRetryTime: time.Second / 100})

0 commit comments

Comments
 (0)