2
0

retry.go 1.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. package retry
  2. import (
  3. "context"
  4. "fmt"
  5. "math/rand"
  6. "time"
  7. "github.com/opencost/opencost/core/pkg/util/defaults"
  8. )
  9. // RetryCancellationErr is the error type that's returned if the retry is cancelled
  10. var RetryCancellationErr error = fmt.Errorf("RetryCancellationErr")
  11. // IsRetryCancelledError returns true if the error was a cancellation
  12. func IsRetryCancelledError(err error) bool {
  13. return err != nil && err.Error() == "RetryCancellationErr"
  14. }
  15. // Retry will run the f func until we receive a non error result up to the provided attempts or a cancellation.
  16. func Retry[T any](ctx context.Context, f func() (T, error), attempts uint, delay time.Duration) (T, error) {
  17. var result T
  18. var err error
  19. d := delay
  20. for r := attempts; r > 0; r-- {
  21. select {
  22. case <-ctx.Done():
  23. return defaults.Default[T](), RetryCancellationErr
  24. default:
  25. }
  26. result, err = f()
  27. if err == nil {
  28. break
  29. }
  30. time.Sleep(d)
  31. jitter := time.Duration(rand.Int63n(int64(d))) // #nosec No need for a cryptographic strength random here
  32. d = d + jitter/2
  33. }
  34. return result, err
  35. }