nurse/internal/retry/retry.go
Peter Kurfer 0faff1d481
Some checks failed
Renovate / renovate (push) Successful in 1m8s
Go build / build (push) Failing after 2m3s
chore: cleanup, add docs, refactor some quirks and prepare release
2023-12-04 16:59:10 +01:00

42 lines
1.1 KiB
Go

package retry
import (
"context"
"errors"
"time"
)
// Retry executes a function with the given number of attempts and attempt timeouts.
// It returns the last error encountered during the attempts.
// If the context is canceled, it returns the context error (if there is no previous error),
// or the joined error of the last error and the context error (otherwise).
func Retry(ctx context.Context, numberOfAttempts uint, attemptTimeout time.Duration, f func(ctx context.Context, attempt int) error) (lastErr error) {
baseCtx, baseCancel := context.WithTimeout(ctx, time.Duration(numberOfAttempts)*attemptTimeout)
defer baseCancel()
for i := uint(0); i < numberOfAttempts; i++ {
select {
case <-ctx.Done():
if lastErr == nil {
return ctx.Err()
}
return errors.Join(lastErr, ctx.Err())
default:
attemptCtx, attemptCancel := context.WithTimeout(baseCtx, attemptTimeout)
lastErr = f(attemptCtx, int(i))
if lastErr == nil {
attemptCancel()
return nil
}
if attemptCtx.Err() == nil {
<-attemptCtx.Done()
}
attemptCancel()
}
}
return lastErr
}