exponential.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. package backoff
  2. import (
  3. "context"
  4. "time"
  5. )
  6. type ExponentialInterval struct {
  7. current float64
  8. maxInterval float64
  9. minInterval float64
  10. multiplier float64
  11. jitter jitter
  12. }
  13. const (
  14. defaultMaxInterval = float64(time.Minute)
  15. defaultMinInterval = float64(500 * time.Millisecond)
  16. defaultMultiplier = 1.5
  17. )
  18. func NewExponentialInterval(options ...ExponentialOption) *ExponentialInterval {
  19. jitterFactor := 0.0
  20. maxInterval := defaultMaxInterval
  21. minInterval := defaultMinInterval
  22. multiplier := defaultMultiplier
  23. var rng Random
  24. for _, option := range options {
  25. switch option.Ident() {
  26. case identJitterFactor{}:
  27. jitterFactor = option.Value().(float64)
  28. case identMaxInterval{}:
  29. maxInterval = float64(option.Value().(time.Duration))
  30. case identMinInterval{}:
  31. minInterval = float64(option.Value().(time.Duration))
  32. case identMultiplier{}:
  33. multiplier = option.Value().(float64)
  34. case identRNG{}:
  35. rng = option.Value().(Random)
  36. }
  37. }
  38. if minInterval > maxInterval {
  39. minInterval = maxInterval
  40. }
  41. if multiplier <= 1 {
  42. multiplier = defaultMultiplier
  43. }
  44. return &ExponentialInterval{
  45. maxInterval: maxInterval,
  46. minInterval: minInterval,
  47. multiplier: multiplier,
  48. jitter: newJitter(jitterFactor, rng),
  49. }
  50. }
  51. func (g *ExponentialInterval) Next() time.Duration {
  52. var next float64
  53. if g.current == 0 {
  54. next = g.minInterval
  55. } else {
  56. next = g.current * g.multiplier
  57. }
  58. if next > g.maxInterval {
  59. next = g.maxInterval
  60. }
  61. if next < g.minInterval {
  62. next = g.minInterval
  63. }
  64. // Apply jitter *AFTER* we calculate the base interval
  65. next = g.jitter.apply(next)
  66. g.current = next
  67. return time.Duration(next)
  68. }
  69. type ExponentialPolicy struct {
  70. cOptions []ControllerOption
  71. igOptions []ExponentialOption
  72. }
  73. func NewExponentialPolicy(options ...ExponentialOption) *ExponentialPolicy {
  74. var cOptions []ControllerOption
  75. var igOptions []ExponentialOption
  76. for _, option := range options {
  77. switch opt := option.(type) {
  78. case ControllerOption:
  79. cOptions = append(cOptions, opt)
  80. default:
  81. igOptions = append(igOptions, opt)
  82. }
  83. }
  84. return &ExponentialPolicy{
  85. cOptions: cOptions,
  86. igOptions: igOptions,
  87. }
  88. }
  89. func (p *ExponentialPolicy) Start(ctx context.Context) Controller {
  90. ig := NewExponentialInterval(p.igOptions...)
  91. return newController(ctx, ig, p.cOptions...)
  92. }