53 lines
httpclient/retry.go
Retry client that re-attempts failed HTTP requests with linear backoff.
// Package httpclient provides an HTTP client with automatic retry for transient failures.package httpclientimport ( "net/http" "time")
// RetryClient wraps an http.Client and retries on server errors and network failures.type RetryClient struct {client *http.Client
maxRetries intbackoff time.Duration
}
// NewRetryClient returns a RetryClient that retries up to maxRetries additional times// after the first attempt, waiting backoff between each pair of attempts.func NewRetryClient(client *http.Client, maxRetries int, backoff time.Duration) *RetryClient { return &RetryClient{client: client, maxRetries: maxRetries, backoff: backoff}}
// Do executes req and retries on 5xx responses and network errors.// 4xx responses indicate a client error and are returned immediately without retrying.// The request body, if present, is automatically rewound before each retry attempt.func (c *RetryClient) Do(req *http.Request) (*http.Response, error) { var (resp *http.Response
err error)
for attempt := 0; attempt <= c.maxRetries; attempt++ { if attempt > 0 {time.Sleep(c.backoff)
}
resp, err = c.client.Do(req)
if err == nil && !shouldRetry(resp) { return resp, nil}
if resp != nil {resp.Body.Close()
}
}
return resp, err}
// shouldRetry returns true when a response warrants another attempt.// Network errors (nil resp) always warrant a retry.// 4xx client errors must not be retried; only 5xx server errors should be.func shouldRetry(resp *http.Response) bool { if resp == nil { return true}
return resp.StatusCode >= 400}