1package backoff 2 3import ( 4 "math/rand" 5 "time" 6) 7 8type jitter interface { 9 apply(interval float64) float64 10} 11 12func newJitter(jitterFactor float64, rng Random) jitter { 13 if jitterFactor <= 0 || jitterFactor >= 1 { 14 return newNopJitter() 15 } 16 return newRandomJitter(jitterFactor, rng) 17} 18 19type nopJitter struct{} 20 21func newNopJitter() *nopJitter { 22 return &nopJitter{} 23} 24 25func (j *nopJitter) apply(interval float64) float64 { 26 return interval 27} 28 29type randomJitter struct { 30 jitterFactor float64 31 rng Random 32} 33 34func newRandomJitter(jitterFactor float64, rng Random) *randomJitter { 35 if rng == nil { 36 // if we have a jitter factor, and no RNG is provided, create one. 37 // This is definitely not "secure", but well, if you care enough, 38 // you would provide one 39 rng = rand.New(rand.NewSource(time.Now().UnixNano())) 40 } 41 42 return &randomJitter{ 43 jitterFactor: jitterFactor, 44 rng: rng, 45 } 46} 47 48func (j *randomJitter) apply(interval float64) float64 { 49 jitterDelta := interval * j.jitterFactor 50 jitterMin := interval - jitterDelta 51 jitterMax := interval + jitterDelta 52 53 // Get a random value from the range [minInterval, maxInterval]. 54 // The formula used below has a +1 because if the minInterval is 1 and the maxInterval is 3 then 55 // we want a 33% chance for selecting either 1, 2 or 3. 56 // 57 // see also: https://github.com/cenkalti/backoff/blob/c2975ffa541a1caeca5f76c396cb8c3e7b3bb5f8/exponential.go#L154-L157 58 return jitterMin + j.rng.Float64()*(jitterMax-jitterMin+1) 59} 60