k3s/vendor/github.com/Rican7/retry/jitter/jitter.go
2019-11-10 04:05:59 +00:00

90 lines
3.1 KiB
Go

// Package jitter provides methods of transforming durations.
//
// Copyright © 2016 Trevor N. Suarez (Rican7)
package jitter
import (
"math"
"math/rand"
"time"
)
// Transformation defines a function that calculates a time.Duration based on
// the given duration.
type Transformation func(duration time.Duration) time.Duration
// Full creates a Transformation that transforms a duration into a result
// duration in [0, n) randomly, where n is the given duration.
//
// The given generator is what is used to determine the random transformation.
// If a nil generator is passed, a default one will be provided.
//
// Inspired by https://www.awsarchitectureblog.com/2015/03/backoff.html
func Full(generator *rand.Rand) Transformation {
random := fallbackNewRandom(generator)
return func(duration time.Duration) time.Duration {
return time.Duration(random.Int63n(int64(duration)))
}
}
// Equal creates a Transformation that transforms a duration into a result
// duration in [n/2, n) randomly, where n is the given duration.
//
// The given generator is what is used to determine the random transformation.
// If a nil generator is passed, a default one will be provided.
//
// Inspired by https://www.awsarchitectureblog.com/2015/03/backoff.html
func Equal(generator *rand.Rand) Transformation {
random := fallbackNewRandom(generator)
return func(duration time.Duration) time.Duration {
return (duration / 2) + time.Duration(random.Int63n(int64(duration))/2)
}
}
// Deviation creates a Transformation that transforms a duration into a result
// duration that deviates from the input randomly by a given factor.
//
// The given generator is what is used to determine the random transformation.
// If a nil generator is passed, a default one will be provided.
//
// Inspired by https://developers.google.com/api-client-library/java/google-http-java-client/backoff
func Deviation(generator *rand.Rand, factor float64) Transformation {
random := fallbackNewRandom(generator)
return func(duration time.Duration) time.Duration {
min := int64(math.Floor(float64(duration) * (1 - factor)))
max := int64(math.Ceil(float64(duration) * (1 + factor)))
return time.Duration(random.Int63n(max-min) + min)
}
}
// NormalDistribution creates a Transformation that transforms a duration into a
// result duration based on a normal distribution of the input and the given
// standard deviation.
//
// The given generator is what is used to determine the random transformation.
// If a nil generator is passed, a default one will be provided.
func NormalDistribution(generator *rand.Rand, standardDeviation float64) Transformation {
random := fallbackNewRandom(generator)
return func(duration time.Duration) time.Duration {
return time.Duration(random.NormFloat64()*standardDeviation + float64(duration))
}
}
// fallbackNewRandom returns the passed in random instance if it's not nil,
// and otherwise returns a new random instance seeded with the current time.
func fallbackNewRandom(random *rand.Rand) *rand.Rand {
// Return the passed in value if it's already not null
if nil != random {
return random
}
seed := time.Now().UnixNano()
return rand.New(rand.NewSource(seed))
}