github.com/iotexproject/iotex-core@v1.14.1-rc1/pkg/routine/recurringtask.go (about) 1 // Copyright (c) 2018 IoTeX 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package routine 7 8 import ( 9 "context" 10 "time" 11 12 "github.com/facebookgo/clock" 13 14 "github.com/iotexproject/iotex-core/pkg/lifecycle" 15 ) 16 17 var _ lifecycle.StartStopper = (*RecurringTask)(nil) 18 19 // RecurringTaskOption is option to RecurringTask. 20 type RecurringTaskOption interface { 21 SetRecurringTaskOption(*RecurringTask) 22 } 23 24 // RecurringTask represents a recurring task 25 type RecurringTask struct { 26 lifecycle.Readiness 27 t Task 28 interval time.Duration 29 ticker *clock.Ticker 30 done chan struct{} 31 clock clock.Clock 32 } 33 34 // NewRecurringTask creates an instance of RecurringTask 35 func NewRecurringTask(t Task, i time.Duration, ops ...RecurringTaskOption) *RecurringTask { 36 rt := &RecurringTask{ 37 t: t, 38 interval: i, 39 done: make(chan struct{}), 40 clock: clock.New(), 41 } 42 for _, opt := range ops { 43 opt.SetRecurringTaskOption(rt) 44 } 45 return rt 46 } 47 48 // Start starts the timer 49 func (t *RecurringTask) Start(_ context.Context) error { 50 t.ticker = t.clock.Ticker(t.interval) 51 ready := make(chan struct{}) 52 go func() { 53 close(ready) 54 for { 55 select { 56 case <-t.done: 57 return 58 case <-t.ticker.C: 59 t.t() 60 } 61 } 62 }() 63 // ensure the goroutine has been running 64 <-ready 65 return t.TurnOn() 66 } 67 68 // Stop stops the timer 69 func (t *RecurringTask) Stop(_ context.Context) error { 70 // prevent stop is called before start. 71 if err := t.TurnOff(); err != nil { 72 return err 73 } 74 if t.ticker != nil { 75 t.ticker.Stop() 76 } 77 close(t.done) 78 return nil 79 }