jitter.go 1.5 KB

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