diff --git a/registry/remote/retry/policy.go b/registry/remote/retry/policy.go index fe7fadee7..ef4670ce2 100644 --- a/registry/remote/retry/policy.go +++ b/registry/remote/retry/policy.go @@ -18,7 +18,7 @@ package retry import ( "hash/maphash" "math" - "math/rand" + "math/rand/v2" "net" "net/http" "strconv" @@ -88,15 +88,15 @@ type Backoff func(attempt int, resp *http.Response) time.Duration // jitter. The backoff is calculated as: // // temp = backoff * factor ^ attempt -// interval = temp * (1 - jitter) + rand.Int63n(2 * jitter * temp) +// interval = temp * (1 - jitter) + rand.Int64N(2 * jitter * temp) // // The HTTP response is checked for a Retry-After header. If it is present, the // value is used as the backoff duration. func ExponentialBackoff(backoff time.Duration, factor, jitter float64) Backoff { return func(attempt int, resp *http.Response) time.Duration { - var h maphash.Hash - h.SetSeed(maphash.MakeSeed()) - rand := rand.New(rand.NewSource(int64(h.Sum64()))) + hashSeed := seedFromMapHash() + timeSeed := uint64(time.Now().UnixNano()) + rand := rand.New(rand.NewPCG(hashSeed, timeSeed)) // check Retry-After if resp != nil && resp.StatusCode == http.StatusTooManyRequests { @@ -109,10 +109,17 @@ func ExponentialBackoff(backoff time.Duration, factor, jitter float64) Backoff { // do exponential backoff with jitter temp := float64(backoff) * math.Pow(factor, float64(attempt)) - return time.Duration(temp*(1-jitter)) + time.Duration(rand.Int63n(int64(2*jitter*temp))) + return time.Duration(temp*(1-jitter)) + time.Duration(rand.Int64N(int64(2*jitter*temp))) } } +// seedFromMapHash returns a seed generated by maphash. +func seedFromMapHash() uint64 { + var h maphash.Hash + h.SetSeed(maphash.MakeSeed()) + return h.Sum64() +} + // GenericPolicy is a generic retry policy. type GenericPolicy struct { // Retryable is a predicate that returns true if the request should be