1 回答
TA贡献1875条经验 获得超3个赞
好的,我想通了。
在这里用解决方案去游乐场
我的 go 版本是 Go 1.17。如果您在 go playground(Go 版本 1.19)中运行上述代码,重试有效。
对于 Go 1.17,retryable-http(v1.0.2) 不处理状态错误代码
func DefaultRetryPolicy() func(ctx context.Context, resp *http.Response, err error) (bool, error) {
return func(ctx context.Context, resp *http.Response, err error) (bool, error) {
// do not retry on context.Canceled or context.DeadlineExceeded
//fmt.Printf("jkajsuiohsd %v\n", ctx.Err())
if ctx.Err() != nil {
return false, ctx.Err()
}
if err != nil {
if v, ok := err.(*url.Error); ok {
// Don't retry if the error was due to too many redirects.
if redirectsErrorRegex.MatchString(v.Error()) {
return false, nil
}
// Don't retry if the error was due to an invalid protocol scheme.
if schemeErrorRegex.MatchString(v.Error()) {
return false, nil
}
// Don't retry if the error was due to TLS cert verification failure.
if _, ok := v.Err.(x509.UnknownAuthorityError); ok {
return false, nil
}
}
// The error is likely recoverable so retry.
return true, nil
}
//EXPECT HANDLING BASED ON STATUS CODES, BUT ABSENT
return false, nil
}
}
对于 Go 1.19,retryable-http(v2.1) 实现了如下baseRetryPolicy所示的功能
func baseRetryPolicy(resp *http.Response, err error) (bool, error) {
if err != nil {
if v, ok := err.(*url.Error); ok {
// Don't retry if the error was due to too many redirects.
if redirectsErrorRe.MatchString(v.Error()) {
return false, v
}
// Don't retry if the error was due to an invalid protocol scheme.
if schemeErrorRe.MatchString(v.Error()) {
return false, v
}
// Don't retry if the error was due to TLS cert verification failure.
if notTrustedErrorRe.MatchString(v.Error()) {
return false, v
}
if _, ok := v.Err.(x509.UnknownAuthorityError); ok {
return false, v
}
}
// The error is likely recoverable so retry.
return true, nil
}
// 429 Too Many Requests is recoverable. Sometimes the server puts
// a Retry-After response header to indicate when the server is
// available to start processing request from client.
if resp.StatusCode == http.StatusTooManyRequests {
return true, nil
}
// Check the response code. We retry on 500-range responses to allow
// the server time to recover, as 500's are typically not permanent
// errors and may relate to outages on the server side. This will catch
// invalid response codes as well, like 0 and 999.
//THIS PART HERE FLAGS RETRIES ON STATUS CODES!
if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != http.StatusNotImplemented) {
return true, fmt.Errorf("unexpected HTTP status %s", resp.Status)
}
return false, nil
}
最后,有以下选项。
移动到 1.19
尝试使用 go-retryablehttp v2.01
如果您要使用 Go.17,请通过如下更新 CheckRetry 函数来创建自定义重试策略。
func TestCreateToolsClient(t *testing.T) {
ts := httptest.NewServer(http.HandlerFunc(InternalServerErrorHandler))
defer ts.Close()
request, err := retryablehttp.NewRequest(http.MethodGet, ts.URL, nil)
if err != nil {
log.Fatal(err)
}
var options retryablehttp.Options
options.RetryWaitMin = 10 * time.Millisecond
options.RetryWaitMax = 50 * time.Millisecond
options.RetryMax = 6
options.Timeout = 60 * time.Second
//options.Timeout = 30000 * time.Millisecond
retryableClient := retryablehttp.NewClient(options)
retryCount := -1
// to verify from stdout if the # of retry actually is getting counted
retryableClient.RequestLogHook = func(req *http.Request, retryNumber int) {
retryCount = retryNumber
log.Println("Retrying")
}
// A regular expression to match the error returned by net/http when the
// configured number of redirects is exhausted. This error isn't typed
// specifically so we resort to matching on the error string.
redirectsErrorRe := regexp.MustCompile(`stopped after \d+ redirects\z`)
// A regular expression to match the error returned by net/http when the
// scheme specified in the URL is invalid. This error isn't typed
// specifically so we resort to matching on the error string.
schemeErrorRe := regexp.MustCompile(`unsupported protocol scheme`)
// A regular expression to match the error returned by net/http when the
// TLS certificate is not trusted. This error isn't typed
// specifically so we resort to matching on the error string.
notTrustedErrorRe := regexp.MustCompile(`certificate is not trusted`)
retryableClient.CheckRetry = func(_ context.Context, resp *http.Response, err error) (bool, error) {
if err != nil {
if v, ok := err.(*url.Error); ok {
// Don't retry if the error was due to too many redirects.
if redirectsErrorRe.MatchString(v.Error()) {
return false, v
}
// Don't retry if the error was due to an invalid protocol scheme.
if schemeErrorRe.MatchString(v.Error()) {
return false, v
}
// Don't retry if the error was due to TLS cert verification failure.
if notTrustedErrorRe.MatchString(v.Error()) {
return false, v
}
if _, ok := v.Err.(x509.UnknownAuthorityError); ok {
return false, v
}
}
// The error is likely recoverable so retry.
return true, nil
}
// 429 Too Many Requests is recoverable. Sometimes the server puts
// a Retry-After response header to indicate when the server is
// available to start processing request from client.
if resp.StatusCode == http.StatusTooManyRequests {
return true, nil
}
// Check the response code. We retry on 500-range responses to allow
// the server time to recover, as 500's are typically not permanent
// errors and may relate to outages on the server side. This will catch
// invalid response codes as well, like 0 and 999.
if resp.StatusCode == 0 || (resp.StatusCode >= 500 && resp.StatusCode != http.StatusNotImplemented) {
return true, fmt.Errorf("unexpected HTTP status %s", resp.Status)
}
return false, nil
}
- 1 回答
- 0 关注
- 88 浏览
添加回答
举报