You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
go-library/vendor/github.com/qiniu/go-sdk/v7/internal/clientv2/interceptor_retry_hosts.go

124 lines
3.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package clientv2
import (
"github.com/qiniu/go-sdk/v7/internal/hostprovider"
"net/http"
"net/url"
"strings"
"time"
)
type HostsRetryConfig struct {
RetryConfig RetryConfig // 主备域名重试参数
HostFreezeDuration time.Duration // 主备域名冻结时间默认600s当一个域名请求失败被冻结的时间最小 time.Millisecond
HostProvider hostprovider.HostProvider // 备用域名获取方法
ShouldFreezeHost func(req *http.Request, resp *http.Response, err error) bool
}
func (c *HostsRetryConfig) init() {
if c.RetryConfig.ShouldRetry == nil {
c.RetryConfig.ShouldRetry = func(req *http.Request, resp *http.Response, err error) bool {
return isHostRetryable(req, resp, err)
}
}
if c.RetryConfig.RetryMax < 0 {
c.RetryConfig.RetryMax = 1
}
c.RetryConfig.init()
if c.HostFreezeDuration < time.Millisecond {
c.HostFreezeDuration = 600 * time.Second
}
if c.ShouldFreezeHost == nil {
c.ShouldFreezeHost = func(req *http.Request, resp *http.Response, err error) bool {
return true
}
}
}
type hostsRetryInterceptor struct {
options HostsRetryConfig
}
func NewHostsRetryInterceptor(options HostsRetryConfig) Interceptor {
return &hostsRetryInterceptor{
options: options,
}
}
func (interceptor *hostsRetryInterceptor) Priority() InterceptorPriority {
return InterceptorPriorityRetryHosts
}
func (interceptor *hostsRetryInterceptor) Intercept(req *http.Request, handler Handler) (resp *http.Response, err error) {
if interceptor == nil || req == nil {
return handler(req)
}
interceptor.options.init()
// 不重试
if interceptor.options.RetryConfig.RetryMax <= 0 {
return handler(req)
}
for i := 0; ; i++ {
// Clone 防止后面 Handler 处理对 req 有污染
reqBefore := cloneReq(req.Context(), req)
resp, err = handler(req)
if !interceptor.options.RetryConfig.ShouldRetry(reqBefore, resp, err) {
return resp, err
}
// 尝试冻结域名
oldHost := req.URL.Host
if interceptor.options.ShouldFreezeHost(req, resp, err) {
if fErr := interceptor.options.HostProvider.Freeze(oldHost, err, interceptor.options.HostFreezeDuration); fErr != nil {
break
}
}
if i >= interceptor.options.RetryConfig.RetryMax {
break
}
// 尝试更换域名
newHost, pErr := interceptor.options.HostProvider.Provider()
if pErr != nil {
break
}
if len(newHost) == 0 {
break
}
if newHost != oldHost {
urlString := req.URL.String()
urlString = strings.Replace(urlString, oldHost, newHost, 1)
u, ppErr := url.Parse(urlString)
if ppErr != nil {
break
}
reqBefore.Host = u.Host
reqBefore.URL = u
}
req = reqBefore
retryInterval := interceptor.options.RetryConfig.RetryInterval()
if retryInterval < time.Microsecond {
continue
}
time.Sleep(retryInterval)
}
return resp, err
}
func isHostRetryable(req *http.Request, resp *http.Response, err error) bool {
return isRequestRetryable(req) && (isResponseRetryable(resp) || IsErrorRetryable(err))
}