attempt.go 1.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. package util
  2. import (
  3. "time"
  4. )
  5. // AttemptStrategy is reused from the goamz package
  6. // AttemptStrategy represents a strategy for waiting for an action
  7. // to complete successfully. This is an internal type used by the
  8. // implementation of other packages.
  9. type AttemptStrategy struct {
  10. Total time.Duration // total duration of attempt.
  11. Delay time.Duration // interval between each try in the burst.
  12. Min int // minimum number of retries; overrides Total
  13. }
  14. type Attempt struct {
  15. strategy AttemptStrategy
  16. last time.Time
  17. end time.Time
  18. force bool
  19. count int
  20. }
  21. // Start begins a new sequence of attempts for the given strategy.
  22. func (s AttemptStrategy) Start() *Attempt {
  23. now := time.Now()
  24. return &Attempt{
  25. strategy: s,
  26. last: now,
  27. end: now.Add(s.Total),
  28. force: true,
  29. }
  30. }
  31. // Next waits until it is time to perform the next attempt or returns
  32. // false if it is time to stop trying.
  33. func (a *Attempt) Next() bool {
  34. now := time.Now()
  35. sleep := a.nextSleep(now)
  36. if !a.force && !now.Add(sleep).Before(a.end) && a.strategy.Min <= a.count {
  37. return false
  38. }
  39. a.force = false
  40. if sleep > 0 && a.count > 0 {
  41. time.Sleep(sleep)
  42. now = time.Now()
  43. }
  44. a.count++
  45. a.last = now
  46. return true
  47. }
  48. func (a *Attempt) nextSleep(now time.Time) time.Duration {
  49. sleep := a.strategy.Delay - now.Sub(a.last)
  50. if sleep < 0 {
  51. return 0
  52. }
  53. return sleep
  54. }
  55. // HasNext returns whether another attempt will be made if the current
  56. // one fails. If it returns true, the following call to Next is
  57. // guaranteed to return true.
  58. func (a *Attempt) HasNext() bool {
  59. if a.force || a.strategy.Min > a.count {
  60. return true
  61. }
  62. now := time.Now()
  63. if now.Add(a.nextSleep(now)).Before(a.end) {
  64. a.force = true
  65. return true
  66. }
  67. return false
  68. }