You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

backoff.go 1.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. // Copyright 2023 The Gitea Authors. All rights reserved.
  2. // SPDX-License-Identifier: MIT
  3. package queue
  4. import (
  5. "context"
  6. "time"
  7. )
  8. const (
  9. backoffBegin = 50 * time.Millisecond
  10. backoffUpper = 2 * time.Second
  11. )
  12. type (
  13. backoffFuncRetErr[T any] func() (retry bool, ret T, err error)
  14. backoffFuncErr func() (retry bool, err error)
  15. )
  16. func backoffRetErr[T any](ctx context.Context, begin, upper time.Duration, end <-chan time.Time, fn backoffFuncRetErr[T]) (ret T, err error) {
  17. d := begin
  18. for {
  19. // check whether the context has been cancelled or has reached the deadline, return early
  20. select {
  21. case <-ctx.Done():
  22. return ret, ctx.Err()
  23. case <-end:
  24. return ret, context.DeadlineExceeded
  25. default:
  26. }
  27. // call the target function
  28. retry, ret, err := fn()
  29. if err != nil {
  30. return ret, err
  31. }
  32. if !retry {
  33. return ret, nil
  34. }
  35. // wait for a while before retrying, and also respect the context & deadline
  36. select {
  37. case <-ctx.Done():
  38. return ret, ctx.Err()
  39. case <-time.After(d):
  40. d *= 2
  41. if d > upper {
  42. d = upper
  43. }
  44. case <-end:
  45. return ret, context.DeadlineExceeded
  46. }
  47. }
  48. }
  49. func backoffErr(ctx context.Context, begin, upper time.Duration, end <-chan time.Time, fn backoffFuncErr) error {
  50. _, err := backoffRetErr(ctx, begin, upper, end, func() (retry bool, ret any, err error) {
  51. retry, err = fn()
  52. return retry, nil, err
  53. })
  54. return err
  55. }