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