60 lines
1.0 KiB
Go
60 lines
1.0 KiB
Go
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)
|
|
}
|