package retry import ( "math" "math/rand" "sync" "time" ) type service struct { mu sync.Mutex rnd *rand.Rand } // New creates retry policy service. func New() Policy { return &service{rnd: rand.New(rand.NewSource(time.Now().UnixNano()))} } func (s *service) NextAttempt(attempt int, now time.Time, minDelay, maxDelay time.Duration, jitterRatio float64) time.Time { if attempt < 1 { attempt = 1 } if minDelay <= 0 { minDelay = time.Second } if maxDelay < minDelay { maxDelay = minDelay } base := float64(minDelay) delay := time.Duration(base * math.Pow(2, float64(attempt-1))) if delay > maxDelay { delay = maxDelay } if jitterRatio > 0 { if jitterRatio > 1 { jitterRatio = 1 } maxJitter := int64(float64(delay) * jitterRatio) if maxJitter > 0 { s.mu.Lock() jitter := s.rnd.Int63n((maxJitter * 2) + 1) s.mu.Unlock() delta := jitter - maxJitter delay += time.Duration(delta) } } if delay < minDelay { delay = minDelay } if delay > maxDelay { delay = maxDelay } return now.UTC().Add(delay) }