package common import ( "errors" "net" "net/http" "time" "go.uber.org/zap" ) type AccessPlatformAPIWithRetryParams struct { MaxExceedLimitRetryCount int MaxRecoverableRetryCount int SleepSecondWhenExceedLimit time.Duration Client *http.Client Request *http.Request SugarLogger *zap.SugaredLogger } const ( PAErrorLevelSuccess = 0 PAErrorLevelExceedLimit = 1 PAErrorLevelRecoverable = 2 PAErrorLevelFailed = 3 ) var ( ErrRecoverableErrMaxRetry = errors.New("recoverable error reach max retry count!") ErrLimitReachMaxRetry = errors.New("Reach max retry count!") ErrHttpCode = errors.New("HTTP Code is not 200") ErrBusinessCode = errors.New("Business code is not ok") ) func AccessPlatformAPIWithRetry(params *AccessPlatformAPIWithRetryParams, handleResponse func(response *http.Response) (int, error)) error { exceedLimitRetryCount := 0 recoverableErrorRetryCount := 0 for { response, err := params.Client.Do(params.Request) if err != nil { params.SugarLogger.Debugf("client.Get return err:%v", err) err, ok := err.(net.Error) recoverableErrorRetryCount++ if ok && err.Timeout() && recoverableErrorRetryCount <= params.MaxRecoverableRetryCount { continue } else { return err } } defer response.Body.Close() if response.StatusCode != 200 { params.SugarLogger.Debugf("http code is:%d", response.StatusCode) recoverableErrorRetryCount++ if recoverableErrorRetryCount <= params.MaxRecoverableRetryCount { continue } return ErrHttpCode } errLevel, err := handleResponse(response) if err != nil { return err } if errLevel == PAErrorLevelSuccess { return nil } else if errLevel == PAErrorLevelExceedLimit { exceedLimitRetryCount++ if exceedLimitRetryCount <= params.MaxExceedLimitRetryCount { time.Sleep(params.SleepSecondWhenExceedLimit) } else { return ErrLimitReachMaxRetry } } else if errLevel == PAErrorLevelRecoverable { if recoverableErrorRetryCount <= params.MaxRecoverableRetryCount { continue } return ErrRecoverableErrMaxRetry } else { return ErrBusinessCode } } }