func()

in exponential/exponential.go [193:264]


func (b *Backoff) Retry(ctx context.Context, op Op, options ...RetryOption) error {
	r := Record{Attempt: 1}

	// Make our first attempt.
	err := op(ctx, r)
	if err == nil {
		return nil
	}

	// Well, that didn't work, so let's start our retry work.
	r.Err = err
	baseInterval := b.policy.InitialInterval
	realInterval := b.randomize(baseInterval)

	for {
		err = b.applyTransformers(err)

		if errors.Is(err, ErrPermanent) {
			return err
		}

		if b.policy.MaxAttempts > 0 && r.Attempt >= b.policy.MaxAttempts {
			return fmt.Errorf("exceeded max attempts: %w: %w", r.Err, ErrPermanent)
		}

		// Check to see if the error contained an interval that is longer
		// than the exponential retry timer. If it is, we will use the error
		// retry timer.
		realInterval = b.intervalSpecified(err, realInterval)

		// If our context is done or our interval goes over the context deadline,
		// then we are done.
		if !b.ctxOK(ctx, realInterval) {
			return fmt.Errorf("r.Err: %w", ErrRetryCanceled)
		}

		// Do this if they did not pass the WithTesting() option.
		if !b.useTest {
			timer := b.newTimer(realInterval)
			select {
			case <-ctx.Done():
				timer.Stop() // Prevent goroutine leak
				return fmt.Errorf("%w: %w ", r.Err, ErrRetryCanceled)
			case <-timer.C:
			}
		}

		// Record attempt last attempt number, our last interval and total interval.
		r.LastInterval = realInterval
		r.TotalInterval += realInterval
		r.Attempt++

		// NO WHAMMIES, NO WHAMMIES, STOP!
		// https://www.youtube.com/watch?v=1mGrM72Z4-Y
		err = op(ctx, r)
		if err == nil {
			return nil
		}

		// Captures our last error in the record.
		r.Err = err

		// Create our new base interval for the next attempt.
		baseInterval = time.Duration(float64(baseInterval) * b.policy.Multiplier)
		// Our base interval cannot exceed the maximum interval.
		if baseInterval > b.policy.MaxInterval {
			baseInterval = b.policy.MaxInterval
		}
		// Randomize the interval based on our randomization factor.
		realInterval = b.randomize(baseInterval)
	}
}