在go项目中,使用 resty 。在http请求中,添加重试条件,在满足条件时才可以重试。使用中,后端所连的服务突然挂线,导致端口不存在,进而引发 connect refused 的错误。而又由于设置超时时间为 30s,导致在服务器响应前,请求方已经断开而报超时的问题。
0x02 代码片断var client = resty.New()
func init() {
client.SetRetryCount(5)
client.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
client.SetRetryWaitTime(time.Second * time.Duration(2))
client.AddRetryCondition(func(response *resty.Response) (b bool, err error) {
if response == nil || response.StatusCode() == 0 || (response.StatusCode() >= http.StatusLocked && response.StatusCode() < http.StatusNotExtended) {
return false, nil
} else {
return true, nil
}
})
}
// GetFromBackServer 从后端服务获取数据
func GetFromBackServer() {
resp, err := client.R().Post("http://127.0.0.1:8083/v2/hello")
if err != nil {
fmt.Printf("err:%s", err.Error())
return
}
fmt.Printf("resp:%+v", resp)
}
response.StatusCodefalse
0x03 跟踪调试
gopkg.in/resty.v1/request.go
_ = Backoff(
func() (*Response, error) {
attempt++
r.URL = r.selectAddr(addrs, url, attempt)
resp, err = r.client.execute(r)
if err != nil {
r.client.Log.Printf("ERROR %v, Attempt %v", err, attempt)
if r.isContextCancelledIfAvailable() {
// stop Backoff from retrying request if request has been
// canceled by context
return resp, nil
}
}
return resp, err
},
Retries(r.client.RetryCount),
WaitTime(r.client.RetryWaitTime),
MaxWaitTime(r.client.RetryMaxWaitTime),
RetryConditions(r.client.RetryConditions),
)
Backoffgopkg.in/resty.v1/resty.go
// Backoff retries with increasing timeout duration up until X amount of retries
// (Default is 3 attempts, Override with option Retries(n))
func Backoff(operation func() (*Response, error), options ...Option) error {
...
for attempt := 0; attempt < opts.maxRetries; attempt++ {
resp, err = operation()
var needsRetry bool
var conditionErr error
for _, condition := range opts.retryConditions {
needsRetry, conditionErr = condition(resp)
if needsRetry || conditionErr != nil {
break
}
}
if err == nil && !needsRetry && conditionErr == nil {
return nil
}
temp := math.Min(capLevel, base*math.Exp2(float64(attempt)))
ri := int(temp / 2)
if ri <= 0 {
ri = 1<<31 - 1 // max int for arch 386
}
sleepDuration := time.Duration(math.Abs(float64(ri + rand.Intn(ri))))
if sleepDuration < opts.waitTime {
sleepDuration = opts.waitTime
}
time.Sleep(sleepDuration)
}
return err
}
forerr
if err == nil && !needsRetry && conditionErr == nil {
return nil
}
条件不满足,所以一直循环