package backoff
import (
"math/rand"
"time"
)
type ExponentialBackOff struct {
InitialInterval time .Duration
RandomizationFactor float64
Multiplier float64
MaxInterval time .Duration
MaxElapsedTime time .Duration
Stop time .Duration
Clock Clock
currentInterval time .Duration
startTime time .Time
}
type Clock interface {
Now () time .Time
}
type ExponentialBackOffOpts func (*ExponentialBackOff )
const (
DefaultInitialInterval = 500 * time .Millisecond
DefaultRandomizationFactor = 0.5
DefaultMultiplier = 1.5
DefaultMaxInterval = 60 * time .Second
DefaultMaxElapsedTime = 15 * time .Minute
)
func NewExponentialBackOff (opts ...ExponentialBackOffOpts ) *ExponentialBackOff {
b := &ExponentialBackOff {
InitialInterval : DefaultInitialInterval ,
RandomizationFactor : DefaultRandomizationFactor ,
Multiplier : DefaultMultiplier ,
MaxInterval : DefaultMaxInterval ,
MaxElapsedTime : DefaultMaxElapsedTime ,
Stop : Stop ,
Clock : SystemClock ,
}
for _ , fn := range opts {
fn (b )
}
b .Reset ()
return b
}
func WithInitialInterval (duration time .Duration ) ExponentialBackOffOpts {
return func (ebo *ExponentialBackOff ) {
ebo .InitialInterval = duration
}
}
func WithRandomizationFactor (randomizationFactor float64 ) ExponentialBackOffOpts {
return func (ebo *ExponentialBackOff ) {
ebo .RandomizationFactor = randomizationFactor
}
}
func WithMultiplier (multiplier float64 ) ExponentialBackOffOpts {
return func (ebo *ExponentialBackOff ) {
ebo .Multiplier = multiplier
}
}
func WithMaxInterval (duration time .Duration ) ExponentialBackOffOpts {
return func (ebo *ExponentialBackOff ) {
ebo .MaxInterval = duration
}
}
func WithMaxElapsedTime (duration time .Duration ) ExponentialBackOffOpts {
return func (ebo *ExponentialBackOff ) {
ebo .MaxElapsedTime = duration
}
}
func WithRetryStopDuration (duration time .Duration ) ExponentialBackOffOpts {
return func (ebo *ExponentialBackOff ) {
ebo .Stop = duration
}
}
func WithClockProvider (clock Clock ) ExponentialBackOffOpts {
return func (ebo *ExponentialBackOff ) {
ebo .Clock = clock
}
}
type systemClock struct {}
func (t systemClock ) Now () time .Time {
return time .Now ()
}
var SystemClock = systemClock {}
func (b *ExponentialBackOff ) Reset () {
b .currentInterval = b .InitialInterval
b .startTime = b .Clock .Now ()
}
func (b *ExponentialBackOff ) NextBackOff () time .Duration {
elapsed := b .GetElapsedTime ()
next := getRandomValueFromInterval (b .RandomizationFactor , rand .Float64 (), b .currentInterval )
b .incrementCurrentInterval ()
if b .MaxElapsedTime != 0 && elapsed +next > b .MaxElapsedTime {
return b .Stop
}
return next
}
func (b *ExponentialBackOff ) GetElapsedTime () time .Duration {
return b .Clock .Now ().Sub (b .startTime )
}
func (b *ExponentialBackOff ) incrementCurrentInterval () {
if float64 (b .currentInterval ) >= float64 (b .MaxInterval )/b .Multiplier {
b .currentInterval = b .MaxInterval
} else {
b .currentInterval = time .Duration (float64 (b .currentInterval ) * b .Multiplier )
}
}
func getRandomValueFromInterval (randomizationFactor , random float64 , currentInterval time .Duration ) time .Duration {
if randomizationFactor == 0 {
return currentInterval
}
var delta = randomizationFactor * float64 (currentInterval )
var minInterval = float64 (currentInterval ) - delta
var maxInterval = float64 (currentInterval ) + delta
return time .Duration (minInterval + (random * (maxInterval - minInterval + 1 )))
}
The pages are generated with Golds v0.8.4 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .