50 lines
1.3 KiB
Go
50 lines
1.3 KiB
Go
package retry
|
|
|
|
import (
|
|
"math"
|
|
"time"
|
|
|
|
"github.com/aws/aws-sdk-go-v2/internal/rand"
|
|
"github.com/aws/aws-sdk-go-v2/internal/timeconv"
|
|
)
|
|
|
|
// ExponentialJitterBackoff provides backoff delays with jitter based on the
|
|
// number of attempts.
|
|
type ExponentialJitterBackoff struct {
|
|
maxBackoff time.Duration
|
|
// precomputed number of attempts needed to reach max backoff.
|
|
maxBackoffAttempts float64
|
|
|
|
randFloat64 func() (float64, error)
|
|
}
|
|
|
|
// NewExponentialJitterBackoff returns an ExponentialJitterBackoff configured
|
|
// for the max backoff.
|
|
func NewExponentialJitterBackoff(maxBackoff time.Duration) *ExponentialJitterBackoff {
|
|
return &ExponentialJitterBackoff{
|
|
maxBackoff: maxBackoff,
|
|
maxBackoffAttempts: math.Log2(
|
|
float64(maxBackoff) / float64(time.Second)),
|
|
randFloat64: rand.CryptoRandFloat64,
|
|
}
|
|
}
|
|
|
|
// BackoffDelay returns the duration to wait before the next attempt should be
|
|
// made. Returns an error if unable get a duration.
|
|
func (j *ExponentialJitterBackoff) BackoffDelay(attempt int, err error) (time.Duration, error) {
|
|
if attempt > int(j.maxBackoffAttempts) {
|
|
return j.maxBackoff, nil
|
|
}
|
|
|
|
b, err := j.randFloat64()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// [0.0, 1.0) * 2 ^ attempts
|
|
ri := int64(1 << uint64(attempt))
|
|
delaySeconds := b * float64(ri)
|
|
|
|
return timeconv.FloatSecondsDur(delaySeconds), nil
|
|
}
|