gitee.com/gricks/utils@v1.0.8/backoff/backoff.go (about) 1 package backoff 2 3 import ( 4 "math/rand" 5 "sync" 6 "time" 7 ) 8 9 var ( 10 r = rand.New(rand.NewSource(time.Now().UnixNano())) 11 mu sync.Mutex 12 ) 13 14 func rfloat64() float64 { 15 mu.Lock() 16 v := r.Float64() 17 mu.Unlock() 18 return v 19 } 20 21 // Strategy defines the methodology for backing off 22 type Strategy interface { 23 Backoff(retries int) time.Duration 24 } 25 26 var DefaultStrategy = &Exponential{ 27 BaseDelay: 1.0 * time.Second, 28 Multiplier: 1.6, 29 Jitter: 0.2, 30 MaxDelay: 120 * time.Second, 31 } 32 33 type Exponential struct { 34 // BaseDelay is the amount of time to backoff after the first failure. 35 BaseDelay time.Duration 36 // Multiplier is the factor with which to multiply backoffs after a 37 // failed retry. Should ideally be greater than 1. 38 Multiplier float64 39 // Jitter is the factor with which backoffs are randomized. 40 Jitter float64 41 // MaxDelay is the upper bound of backoff delay. 42 MaxDelay time.Duration 43 } 44 45 func (e Exponential) Backoff(retries int) time.Duration { 46 if retries == 0 { 47 return e.BaseDelay 48 } 49 backoff, max := float64(e.BaseDelay), float64(e.MaxDelay) 50 for backoff < max && retries > 0 { 51 backoff *= e.Multiplier 52 retries-- 53 } 54 if backoff > max { 55 backoff = max 56 } 57 // Randomize backoff delays so that if a cluster of requests start at 58 // the same time, they won't operate in lockstep. 59 backoff *= 1 + e.Jitter*(rfloat64()*2-1) 60 if backoff < 0 { 61 return 0 62 } 63 return time.Duration(backoff) 64 }