jitter_backoff.go (1332B)
1 package retry 2 3 import ( 4 "math" 5 "time" 6 7 "github.com/aws/aws-sdk-go-v2/internal/rand" 8 "github.com/aws/aws-sdk-go-v2/internal/timeconv" 9 ) 10 11 // ExponentialJitterBackoff provides backoff delays with jitter based on the 12 // number of attempts. 13 type ExponentialJitterBackoff struct { 14 maxBackoff time.Duration 15 // precomputed number of attempts needed to reach max backoff. 16 maxBackoffAttempts float64 17 18 randFloat64 func() (float64, error) 19 } 20 21 // NewExponentialJitterBackoff returns an ExponentialJitterBackoff configured 22 // for the max backoff. 23 func NewExponentialJitterBackoff(maxBackoff time.Duration) *ExponentialJitterBackoff { 24 return &ExponentialJitterBackoff{ 25 maxBackoff: maxBackoff, 26 maxBackoffAttempts: math.Log2( 27 float64(maxBackoff) / float64(time.Second)), 28 randFloat64: rand.CryptoRandFloat64, 29 } 30 } 31 32 // BackoffDelay returns the duration to wait before the next attempt should be 33 // made. Returns an error if unable get a duration. 34 func (j *ExponentialJitterBackoff) BackoffDelay(attempt int, err error) (time.Duration, error) { 35 if attempt > int(j.maxBackoffAttempts) { 36 return j.maxBackoff, nil 37 } 38 39 b, err := j.randFloat64() 40 if err != nil { 41 return 0, err 42 } 43 44 // [0.0, 1.0) * 2 ^ attempts 45 ri := int64(1 << uint64(attempt)) 46 delaySeconds := b * float64(ri) 47 48 return timeconv.FloatSecondsDur(delaySeconds), nil 49 }