-
Notifications
You must be signed in to change notification settings - Fork 300
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add retryablehttp Client Option #619
Changes from all commits
ba1c4d4
64f9d85
8cd3b9b
eb9f7c6
e8cc994
1eb3081
6778bc0
0bef781
f363fea
32d5d94
f19d938
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ import ( | |
"time" | ||
|
||
"github.com/google/go-querystring/query" | ||
"github.com/hashicorp/go-retryablehttp" | ||
"golang.org/x/oauth2" | ||
"golang.org/x/time/rate" | ||
) | ||
|
@@ -92,6 +93,29 @@ type Client struct { | |
|
||
// Optional rate limiter to ensure QoS. | ||
rateLimiter *rate.Limiter | ||
|
||
// Optional retry values. Setting the RetryConfig.RetryMax value enables automatically retrying requests | ||
// that fail with 429 or 500-level response codes using the go-retryablehttp client | ||
RetryConfig RetryConfig | ||
} | ||
|
||
// RetryConfig sets the values used for enabling retries and backoffs for | ||
// requests that fail with 429 or 500-level response codes using the go-retryablehttp client. | ||
// RetryConfig.RetryMax must be configured to enable this behavior. RetryConfig.RetryWaitMin and | ||
// RetryConfig.RetryWaitMax are optional, with the default values being 1.0 and 30.0, respectively. | ||
// | ||
// You can use | ||
// | ||
// godo.PtrTo(1.0) | ||
// | ||
// to explicitly set the RetryWaitMin and RetryWaitMax values. | ||
// | ||
// Note: Opting to use the go-retryablehttp client will overwrite any custom HTTP client passed into New(). | ||
danaelhe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Only the custom HTTP client's custom transport and timeout will be maintained. | ||
type RetryConfig struct { | ||
RetryMax int | ||
RetryWaitMin *float64 // Minimum time to wait | ||
RetryWaitMax *float64 // Maximum time to wait | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed RetryWaitMin and RetryWaitMax to pointers to differentiate between an unset variable and a variable set to 0.0. |
||
} | ||
|
||
// RequestCompletionCallback defines the type of the request callback function | ||
|
@@ -271,6 +295,33 @@ func New(httpClient *http.Client, opts ...ClientOpt) (*Client, error) { | |
} | ||
} | ||
|
||
// if retryMax is set it will use the retryablehttp client. | ||
if c.RetryConfig.RetryMax > 0 { | ||
retryableClient := retryablehttp.NewClient() | ||
retryableClient.RetryMax = c.RetryConfig.RetryMax | ||
|
||
if c.RetryConfig.RetryWaitMin != nil { | ||
retryableClient.RetryWaitMin = time.Duration(*c.RetryConfig.RetryWaitMin * float64(time.Second)) | ||
} | ||
if c.RetryConfig.RetryWaitMax != nil { | ||
retryableClient.RetryWaitMax = time.Duration(*c.RetryConfig.RetryWaitMax * float64(time.Second)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An effort to avoid an unset RetryWaitMax and RetryWaitMin with a value of 0.0 overriding the retryablehttp's default value of 30 seconds and 1 second, respectively. |
||
} | ||
|
||
// if timeout is set, it is maintained before overwriting client with StandardClient() | ||
retryableClient.HTTPClient.Timeout = c.client.Timeout | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I find that some opensource packages will also set a timeout, so decided to maintain it as well. |
||
|
||
var source *oauth2.Transport | ||
if _, ok := c.client.Transport.(*oauth2.Transport); ok { | ||
source = c.client.Transport.(*oauth2.Transport) | ||
} | ||
c.client = retryableClient.StandardClient() | ||
danaelhe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
c.client.Transport = &oauth2.Transport{ | ||
Base: c.client.Transport, | ||
Source: source.Source, | ||
} | ||
|
||
} | ||
|
||
return c, nil | ||
} | ||
|
||
|
@@ -315,6 +366,17 @@ func SetStaticRateLimit(rps float64) ClientOpt { | |
} | ||
} | ||
|
||
// WithRetryAndBackoffs sets retry values. Setting the RetryConfig.RetryMax value enables automatically retrying requests | ||
// that fail with 429 or 500-level response codes using the go-retryablehttp client | ||
func WithRetryAndBackoffs(retryConfig RetryConfig) ClientOpt { | ||
return func(c *Client) error { | ||
c.RetryConfig.RetryMax = retryConfig.RetryMax | ||
c.RetryConfig.RetryWaitMax = retryConfig.RetryWaitMax | ||
c.RetryConfig.RetryWaitMin = retryConfig.RetryWaitMin | ||
return nil | ||
} | ||
} | ||
|
||
// NewRequest creates an API request. A relative URL can be provided in urlStr, which will be resolved to the | ||
// BaseURL of the Client. Relative URLS should always be specified without a preceding slash. If specified, the | ||
// value pointed to by body is JSON encoded and included in as the request body. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RetryWaitMax and RetryWaitMin do have default values: https://github.com/hashicorp/go-retryablehttp/blob/main/client.go#L51
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those defaults look good based on the testing I did over the course of looking at this branch, so I'm happy with using those 👍