package platformapi import ( "errors" "net" "net/http" "time" "github.com/fatih/structs" "git.rosy.net.cn/baseapi" ) const ( DefClientTimeout = 10 * time.Second DefSleepSecondWhenExceedLimit = 6 * time.Second DefMaxRecoverableRetryCount = 3 DefMaxExceedLimitRetryCount = 10 ) type APIRetryConfig struct { MaxExceedLimitRetryCount int MaxRecoverableRetryCount int SleepSecondWhenExceedLimit time.Duration } type APIConfig struct { APIRetryConfig ClientTimeout time.Duration } type AccessPlatformAPIWithRetryParam struct { APIRetryConfig Client *http.Client Request *http.Request } var ( DefAPIConfig = APIConfig{ APIRetryConfig: APIRetryConfig{ MaxExceedLimitRetryCount: DefMaxExceedLimitRetryCount, MaxRecoverableRetryCount: DefMaxRecoverableRetryCount, SleepSecondWhenExceedLimit: DefSleepSecondWhenExceedLimit, }, ClientTimeout: DefClientTimeout, } ) const ( ErrLevelSuccess = "JXC4_SUCCESS" ErrLevelExceedLimit = "JXC4_EXCEED_LIMIT" ErrLevelRecoverableErr = "JXC4_RECOVERABLE" ErrLevelGeneralFail = "JXC4_GENERAL_FAIL" ErrLevelCodeIsNotOK = "JXC4_CODE_IS_NOT_OK" ) // common api access error var ( ErrAPIAccessFailed = errors.New("access API failed") ErrHTTPCodeIsNot200 = errors.New("HTTP code is not 200") ErrResponseDataFormatWrong = errors.New("the data of response has wrong format") ) // common callback response var ( ErrStrUnescapeError = "can not unescape data:%v, error:%v" ErrStrUnmarshalError = "can not unmarshal data:%v, error:%v" ErrStrCallbackSignatureIsWrong = "wrong signature" ) func init() { structs.DefaultTagName = "json" } func AccessPlatformAPIWithRetry(client *http.Client, request *http.Request, config *APIConfig, handleResponse func(response *http.Response) (string, error)) error { exceedLimitRetryCount := 0 recoverableErrorRetryCount := 0 for { response, err := client.Do(request) if err != nil { baseapi.SugarLogger.Debugf("AccessPlatformAPIWithRetry client.Get return err:%v", err) err, ok := err.(net.Error) if ok && err.Timeout() && recoverableErrorRetryCount <= config.MaxRecoverableRetryCount { recoverableErrorRetryCount++ continue } else { baseapi.SugarLogger.Errorf("AccessPlatformAPIWithRetry access api request:%v, error:%v", request, err) return ErrAPIAccessFailed } } defer response.Body.Close() if response.StatusCode != 200 { baseapi.SugarLogger.Errorf("AccessPlatformAPIWithRetry HTTP code is:%d, request:%v", response.StatusCode, request) return ErrHTTPCodeIsNot200 } errLevel, err := handleResponse(response) if err == nil { return nil } else if errLevel == ErrLevelExceedLimit { exceedLimitRetryCount++ if exceedLimitRetryCount <= config.MaxExceedLimitRetryCount { time.Sleep(config.SleepSecondWhenExceedLimit) continue } } else if errLevel == ErrLevelRecoverableErr { recoverableErrorRetryCount++ if recoverableErrorRetryCount <= config.MaxRecoverableRetryCount { continue } } baseapi.SugarLogger.Infof("AccessPlatformAPIWithRetry failed, request:%v, response:%v, error:%v", request, response, err) return err } }