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.6KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  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. var (
  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 mockBackoffDuration(d time.Duration) func() {
  17. oldBegin, oldUpper := backoffBegin, backoffUpper
  18. backoffBegin, backoffUpper = d, d
  19. return func() {
  20. backoffBegin, backoffUpper = oldBegin, oldUpper
  21. }
  22. }
  23. func backoffRetErr[T any](ctx context.Context, begin, upper time.Duration, end <-chan time.Time, fn backoffFuncRetErr[T]) (ret T, err error) {
  24. d := begin
  25. for {
  26. // check whether the context has been cancelled or has reached the deadline, return early
  27. select {
  28. case <-ctx.Done():
  29. return ret, ctx.Err()
  30. case <-end:
  31. return ret, context.DeadlineExceeded
  32. default:
  33. }
  34. // call the target function
  35. retry, ret, err := fn()
  36. if err != nil {
  37. return ret, err
  38. }
  39. if !retry {
  40. return ret, nil
  41. }
  42. // wait for a while before retrying, and also respect the context & deadline
  43. select {
  44. case <-ctx.Done():
  45. return ret, ctx.Err()
  46. case <-time.After(d):
  47. d *= 2
  48. if d > upper {
  49. d = upper
  50. }
  51. case <-end:
  52. return ret, context.DeadlineExceeded
  53. }
  54. }
  55. }
  56. func backoffErr(ctx context.Context, begin, upper time.Duration, end <-chan time.Time, fn backoffFuncErr) error {
  57. _, err := backoffRetErr(ctx, begin, upper, end, func() (retry bool, ret any, err error) {
  58. retry, err = fn()
  59. return retry, nil, err
  60. })
  61. return err
  62. }