retrier.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. // Package retrier implements the "retriable" resiliency pattern for Go.
  2. package retrier
  3. import "time"
  4. // Retrier implements the "retriable" resiliency pattern, abstracting out the process of retrying a failed action
  5. // a certain number of times with an optional back-off between each retry.
  6. type Retrier struct {
  7. backoff []time.Duration
  8. class Classifier
  9. }
  10. // New constructs a Retrier with the given backoff pattern and classifier. The length of the backoff pattern
  11. // indicates how many times an action will be retried, and the value at each index indicates the amount of time
  12. // waited before each subsequent retry. The classifier is used to determine which errors should be retried and
  13. // which should cause the retrier to fail fast. The DefaultClassifier is used if nil is passed.
  14. func New(backoff []time.Duration, class Classifier) *Retrier {
  15. if class == nil {
  16. class = DefaultClassifier{}
  17. }
  18. return &Retrier{
  19. backoff: backoff,
  20. class: class,
  21. }
  22. }
  23. // Run executes the given work function, then classifies its return value based on the classifier used
  24. // to construct the Retrier. If the result is Succeed or Fail, the return value of the work function is
  25. // returned to the caller. If the result is Retry, then Run sleeps according to the its backoff policy
  26. // before retrying. If the total number of retries is exceeded then the return value of the work function
  27. // is returned to the caller regardless.
  28. func (r *Retrier) Run(work func() error) error {
  29. retries := 0
  30. for {
  31. ret := work()
  32. switch r.class.Classify(ret) {
  33. case Succeed, Fail:
  34. return ret
  35. case Retry:
  36. if retries >= len(r.backoff) {
  37. return ret
  38. }
  39. time.Sleep(r.backoff[retries])
  40. retries++
  41. }
  42. }
  43. }