github.com/qiniu/go-sdk/v7@v7.27.0/storagev2/backoff/backoff.go (about) 1 package backoff 2 3 import ( 4 "context" 5 "math" 6 "math/rand" 7 "sync" 8 "time" 9 10 "github.com/alex-ant/gomath/rational" 11 ) 12 13 type ( 14 // Backoff 退避器接口 15 Backoff interface { 16 // Time 获取重试的退避时长间隔 17 Time(context.Context, *BackoffOptions) time.Duration 18 } 19 20 // BackoffOptions 退避器选项 21 BackoffOptions struct { 22 // Attempts 重试次数 23 Attempts int 24 } 25 ) 26 27 type customizedBackoff struct { 28 backoffFn func(context.Context, *BackoffOptions) time.Duration 29 } 30 31 // NewBackoff 创建自定义时长的退避器 32 func NewBackoff(fn func(context.Context, *BackoffOptions) time.Duration) Backoff { 33 return customizedBackoff{backoffFn: fn} 34 } 35 36 func (s customizedBackoff) Time(ctx context.Context, options *BackoffOptions) time.Duration { 37 return s.backoffFn(ctx, options) 38 } 39 40 type fixedBackoff struct { 41 wait time.Duration 42 } 43 44 // NewFixedBackoff 创建固定时长的退避器 45 func NewFixedBackoff(wait time.Duration) Backoff { 46 return fixedBackoff{wait: wait} 47 } 48 49 func (s fixedBackoff) Time(context.Context, *BackoffOptions) time.Duration { 50 return s.wait 51 } 52 53 type randomizedBackoff struct { 54 base Backoff 55 minification, magnification rational.Rational 56 r *rand.Rand 57 mutex sync.Mutex 58 } 59 60 // NewRandomizedBackoff 创建随机时长的退避器 61 func NewRandomizedBackoff(base Backoff, minification, magnification rational.Rational) Backoff { 62 if minification.LessThanNum(0) { 63 panic("minification must be greater than or equal to 0") 64 } 65 if magnification.LessThanNum(0) || magnification.GetNumerator() == 0 { 66 panic("magnification must be greater than 0") 67 } 68 return &randomizedBackoff{ 69 base: base, 70 minification: minification, 71 magnification: magnification, 72 r: rand.New(rand.NewSource(time.Now().UnixNano())), 73 } 74 } 75 76 func (s *randomizedBackoff) Time(ctx context.Context, opts *BackoffOptions) time.Duration { 77 b := s.base.Time(ctx, opts) 78 min := s.minification.MultiplyByNum(int64(b)) 79 max := s.magnification.MultiplyByNum(int64(b)) 80 diff := int64(max.Subtract(min).Float64()) 81 s.mutex.Lock() 82 r := s.r.Int63n(diff) 83 s.mutex.Unlock() 84 return time.Duration(min.AddNum(r).Float64()) 85 } 86 87 type limitedBackoff struct { 88 base Backoff 89 min, max time.Duration 90 } 91 92 // NewLimitedBackoff 创建限制时长的退避器 93 func NewLimitedBackoff(base Backoff, min, max time.Duration) Backoff { 94 return &limitedBackoff{ 95 base: base, 96 min: min, 97 max: max, 98 } 99 } 100 101 func (s limitedBackoff) Time(ctx context.Context, opts *BackoffOptions) time.Duration { 102 b := s.base.Time(ctx, opts) 103 if b < s.min { 104 return s.min 105 } else if b > s.max { 106 return s.max 107 } 108 return b 109 } 110 111 type exponentialBackoff struct { 112 wait time.Duration 113 baseNumber int64 114 } 115 116 // NewExponentialBackoff 创建时长指数级增长的退避器 117 func NewExponentialBackoff(wait time.Duration, baseNumber int64) Backoff { 118 return exponentialBackoff{wait: wait, baseNumber: baseNumber} 119 } 120 121 func (e exponentialBackoff) Time(ctx context.Context, opts *BackoffOptions) time.Duration { 122 return e.wait * time.Duration(math.Pow(float64(e.baseNumber), float64(opts.Attempts))) 123 }