mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-14 07:26:47 +00:00
Refactoring the timeout retries into a more general 'retry policy' with support for retrying on HTTP 429 (Too Many Requests) and other responses with a `Retry-After` header The delay between requests is controlled by a combination of a 'backoff' (currently only a simple linear backoff), and honouring the `Retry-After` value (longest delay wins) This makes the 'rate limiter' an optional argument as well, removing the use of `nil` when one isn't supplied Signed-off-by: David Ackroyd <daveo.ackroyd@gmail.com>
56 lines
1.1 KiB
Go
56 lines
1.1 KiB
Go
package request
|
|
|
|
import (
|
|
"net"
|
|
"net/http"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
headerRetryAfter = "Retry-After"
|
|
)
|
|
|
|
// DefaultRetryPolicy determines whether the request should be retried, implemented with a default strategy.
|
|
func DefaultRetryPolicy(resp *http.Response, err error) (bool, error) {
|
|
if err != nil {
|
|
if timeoutErr, ok := err.(net.Error); ok && timeoutErr.Timeout() {
|
|
return true, nil
|
|
}
|
|
return false, err
|
|
}
|
|
|
|
if resp.StatusCode == http.StatusTooManyRequests {
|
|
return true, nil
|
|
}
|
|
|
|
if resp.Header.Get(headerRetryAfter) != "" {
|
|
return true, nil
|
|
}
|
|
|
|
return false, nil
|
|
}
|
|
|
|
// RetryAfter parses the Retry-After header in the response to determine the minimum
|
|
// duration needed to wait before retrying.
|
|
func RetryAfter(resp *http.Response, now time.Time) time.Duration {
|
|
if resp == nil {
|
|
return 0
|
|
}
|
|
|
|
after := resp.Header.Get(headerRetryAfter)
|
|
if after == "" {
|
|
return 0
|
|
}
|
|
|
|
if sec, err := strconv.ParseInt(after, 10, 32); err == nil {
|
|
return time.Duration(sec) * time.Second
|
|
}
|
|
|
|
if when, err := time.Parse(time.RFC1123, after); err == nil {
|
|
return when.Sub(now)
|
|
}
|
|
|
|
return 0
|
|
}
|