func WithRetries()

in internal/requesthelper/retry.go [33:95]


func WithRetries(ctx *log.Context, rm *RequestManager, sf SleepFunc, eTag string) (*http.Response, error) {
	var lastErr error

	for n := 0; n < expRetryN; n++ {
		resp, err := rm.MakeRequest(ctx, eTag)

		// If there was no error, return the response
		if err == nil {
			return resp, nil
		}

		lastErr = err
		ctx.Log("warning", fmt.Sprintf("error on attempt %v: %v", n+1, err))

		status := -1
		if resp != nil {
			if resp.Body != nil { // we are not going to read this response body
				resp.Body.Close()
			}

			status = resp.StatusCode
		}

		// status == -1 means that there wasn't any http request
		if status == -1 {
			te, haste := lastErr.(interface {
				Temporary() bool
			})
			to, hasto := lastErr.(interface {
				Timeout() bool
			})

			if haste || hasto {
				if haste && te.Temporary() {
					ctx.Log("message", fmt.Sprintf("temporary error occurred. Retrying: %v", lastErr))
				} else if hasto && to.Timeout() {
					ctx.Log("message", fmt.Sprintf("timeout error occurred. Retrying: %v", lastErr))
				} else {
					ctx.Log("message", fmt.Sprintf("non-timeout, non-temporary error occurred, skipping retries: %v", lastErr))
					break
				}
			} else {
				ctx.Log("message", "no response returned and unexpected error, skipping retries.")
				break
			}
		} else if responseNotModified(status) {
			return resp, nil
		} else if noImmediateGoalStatesToProcess(status) {
			return resp, nil
		} else if !isTransientHTTPStatusCode(status) {
			ctx.Log("message", fmt.Sprintf("RequestManager returned %v, skipping retries", status))
			break
		}

		if n < expRetryN-1 {
			// have more retries to go, sleep before retrying
			slp := expRetryK * time.Duration(int(math.Pow(float64(expRetryM), float64(n))))
			sf(slp)
		}
	}

	return nil, lastErr
}