66 lines
1.9 KiB
Go
66 lines
1.9 KiB
Go
|
package linodego
|
||
|
|
||
|
import (
|
||
|
"log"
|
||
|
"net/http"
|
||
|
"strconv"
|
||
|
"time"
|
||
|
|
||
|
"github.com/go-resty/resty/v2"
|
||
|
)
|
||
|
|
||
|
// type RetryConditional func(r *resty.Response) (shouldRetry bool)
|
||
|
type RetryConditional resty.RetryConditionFunc
|
||
|
|
||
|
// Configures resty to
|
||
|
// lock until enough time has passed to retry the request as determined by the Retry-After response header.
|
||
|
// If the Retry-After header is not set, we fall back to value of SetPollDelay.
|
||
|
func configureRetries(c *Client) {
|
||
|
c.resty.
|
||
|
SetRetryCount(1000).
|
||
|
AddRetryCondition(checkRetryConditionals(c)).
|
||
|
SetRetryAfter(respectRetryAfter)
|
||
|
}
|
||
|
|
||
|
func checkRetryConditionals(c *Client) func(*resty.Response, error) bool {
|
||
|
return func(r *resty.Response, err error) bool {
|
||
|
for _, retryConditional := range c.retryConditionals {
|
||
|
retry := retryConditional(r, err)
|
||
|
if retry {
|
||
|
log.Printf("[INFO] Received error %s - Retrying", r.Error())
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// SetLinodeBusyRetry configures resty to retry specifically on "Linode busy." errors
|
||
|
// The retry wait time is configured in SetPollDelay
|
||
|
func linodeBusyRetryCondition(r *resty.Response, _ error) bool {
|
||
|
apiError, ok := r.Error().(*APIError)
|
||
|
linodeBusy := ok && apiError.Error() == "Linode busy."
|
||
|
retry := r.StatusCode() == http.StatusBadRequest && linodeBusy
|
||
|
return retry
|
||
|
}
|
||
|
|
||
|
func tooManyRequestsRetryCondition(r *resty.Response, _ error) bool {
|
||
|
return r.StatusCode() == http.StatusTooManyRequests
|
||
|
}
|
||
|
|
||
|
func respectRetryAfter(client *resty.Client, resp *resty.Response) (time.Duration, error) {
|
||
|
retryAfterStr := resp.Header().Get("Retry-After")
|
||
|
if retryAfterStr == "" {
|
||
|
return 0, nil
|
||
|
}
|
||
|
|
||
|
retryAfter, err := strconv.Atoi(retryAfterStr)
|
||
|
if err != nil {
|
||
|
return 0, err
|
||
|
}
|
||
|
|
||
|
duration := time.Duration(retryAfter) * time.Second
|
||
|
log.Printf("[INFO] Respecting Retry-After Header of %d (%s) (max %s)", retryAfter, duration, client.RetryMaxWaitTime)
|
||
|
return duration, nil
|
||
|
}
|