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

12 months ago
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))
}