retry.go 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. // Package retry implements basic helpers for implementing retry policies.
  2. //
  3. // If you are looking to implement a retry policy in an http client, take a
  4. // look at the web package.
  5. package retry
  6. import (
  7. "errors"
  8. "math/rand"
  9. "time"
  10. )
  11. func init() {
  12. rand.Seed(time.Now().UnixNano())
  13. }
  14. // Policy specifies how to execute Run(...).
  15. type Policy struct {
  16. // Attempts to retry
  17. Attempts int
  18. // Sleep is the initial duration to wait before retrying
  19. Sleep time.Duration
  20. // Factor is the backoff rate (2 = double sleep time before next attempt)
  21. Factor int
  22. }
  23. // Double is a convenience Policy which has a initial Sleep of 1 second and
  24. // doubles every subsequent attempt.
  25. func Double(attempts int) *Policy {
  26. return &Policy{
  27. Attempts: attempts,
  28. Factor: 2,
  29. Sleep: time.Second,
  30. }
  31. }
  32. // Run executes a function until:
  33. // 1. A nil error is returned,
  34. // 2. The max number of attempts has been reached,
  35. // 3. A Stop(...) wrapped error is returned
  36. func Run(p *Policy, f func() error) error {
  37. if p == nil {
  38. return errors.New("policy must not be nil")
  39. }
  40. if err := f(); err != nil {
  41. if s, ok := err.(stop); ok {
  42. // Return the original error for later checking
  43. return s.error
  44. }
  45. p.Attempts = p.Attempts - 1
  46. if p.Attempts > 0 {
  47. // Add some randomness to prevent creating a Thundering Herd
  48. jitter := time.Duration(rand.Int63n(int64(p.Sleep)))
  49. p.Sleep = p.Sleep + jitter/time.Duration(p.Factor)
  50. time.Sleep(p.Sleep)
  51. p.Sleep = time.Duration(p.Factor) * p.Sleep
  52. return Run(p, f)
  53. }
  54. return err
  55. }
  56. return nil
  57. }
  58. // Stop wraps an error returned by a retry func and stops subsequent retries.
  59. func Stop(err error) error {
  60. return stop{err}
  61. }
  62. type stop struct {
  63. error
  64. }