Add retry transport with configurable backoff and Retry-After support
Implements retry middleware as a RoundTripper wrapper: - Exponential and constant backoff strategies with jitter - RFC 7231 Retry-After header parsing (seconds and HTTP-date) - Default policy retries idempotent methods on 429/5xx and network errors - Body restoration via GetBody, context cancellation, response body cleanup
This commit is contained in:
64
retry/backoff.go
Normal file
64
retry/backoff.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package retry
|
||||
|
||||
import (
|
||||
"math/rand/v2"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Backoff computes the delay before the next retry attempt.
|
||||
type Backoff interface {
|
||||
// Delay returns the wait duration for the given attempt number (zero-based).
|
||||
Delay(attempt int) time.Duration
|
||||
}
|
||||
|
||||
// ExponentialBackoff returns a Backoff that doubles the delay on each attempt.
|
||||
// The delay is calculated as base * 2^attempt, capped at max. When withJitter
|
||||
// is true, a random duration in [0, delay*0.5) is added.
|
||||
func ExponentialBackoff(base, max time.Duration, withJitter bool) Backoff {
|
||||
return &exponentialBackoff{
|
||||
base: base,
|
||||
max: max,
|
||||
withJitter: withJitter,
|
||||
}
|
||||
}
|
||||
|
||||
// ConstantBackoff returns a Backoff that always returns the same delay.
|
||||
func ConstantBackoff(d time.Duration) Backoff {
|
||||
return constantBackoff{delay: d}
|
||||
}
|
||||
|
||||
type exponentialBackoff struct {
|
||||
base time.Duration
|
||||
max time.Duration
|
||||
withJitter bool
|
||||
}
|
||||
|
||||
func (b *exponentialBackoff) Delay(attempt int) time.Duration {
|
||||
delay := b.base
|
||||
for range attempt {
|
||||
delay *= 2
|
||||
if delay >= b.max {
|
||||
delay = b.max
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if b.withJitter {
|
||||
jitter := time.Duration(rand.Int64N(int64(delay / 2)))
|
||||
delay += jitter
|
||||
}
|
||||
|
||||
if delay > b.max {
|
||||
delay = b.max
|
||||
}
|
||||
|
||||
return delay
|
||||
}
|
||||
|
||||
type constantBackoff struct {
|
||||
delay time.Duration
|
||||
}
|
||||
|
||||
func (b constantBackoff) Delay(_ int) time.Duration {
|
||||
return b.delay
|
||||
}
|
||||
Reference in New Issue
Block a user