periodic.go 1.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. package task
  2. import (
  3. "sync"
  4. "time"
  5. )
  6. // Periodic is a task that runs periodically.
  7. type Periodic struct {
  8. // Interval of the task being run
  9. Interval time.Duration
  10. // Execute is the task function
  11. Execute func() error
  12. // OnFailure will be called when Execute returns non-nil error
  13. OnError func(error)
  14. access sync.Mutex
  15. timer *time.Timer
  16. closed bool
  17. }
  18. func (t *Periodic) checkedExecute() error {
  19. t.access.Lock()
  20. defer t.access.Unlock()
  21. if t.closed {
  22. return nil
  23. }
  24. if err := t.Execute(); err != nil {
  25. return err
  26. }
  27. t.timer = time.AfterFunc(t.Interval, func() {
  28. if err := t.checkedExecute(); err != nil && t.OnError != nil {
  29. t.OnError(err)
  30. }
  31. })
  32. return nil
  33. }
  34. // Start implements common.Runnable. Start must not be called multiple times without Close being called.
  35. func (t *Periodic) Start() error {
  36. t.access.Lock()
  37. t.closed = false
  38. t.access.Unlock()
  39. if err := t.checkedExecute(); err != nil {
  40. t.closed = true
  41. return err
  42. }
  43. return nil
  44. }
  45. // Close implements common.Closable.
  46. func (t *Periodic) Close() error {
  47. t.access.Lock()
  48. defer t.access.Unlock()
  49. t.closed = true
  50. if t.timer != nil {
  51. t.timer.Stop()
  52. t.timer = nil
  53. }
  54. return nil
  55. }