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") ErrRecoverableErrReachMaxRetry = errors.New("recoverable error reach max retry count") ErrLimitExceedReachMaxRetry = errors.New("limit exceed reach max retry count") 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("client.Get return err:%v", err) err, ok := err.(net.Error) recoverableErrorRetryCount++ if ok && err.Timeout() && recoverableErrorRetryCount <= config.MaxRecoverableRetryCount { continue } else { baseapi.SugarLogger.Errorf("access api error:%v", err) return ErrAPIAccessFailed } } defer response.Body.Close() if response.StatusCode != 200 { baseapi.SugarLogger.Errorf("HTTP code not 200, it's:%v", response.StatusCode) 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 { return ErrLimitExceedReachMaxRetry } } else if errLevel == ErrLevelRecoverableErr { recoverableErrorRetryCount++ if recoverableErrorRetryCount <= config.MaxRecoverableRetryCount { continue } return err } return err } }