generated from atomicgo/template
-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathschedule.go
136 lines (118 loc) · 2.97 KB
/
schedule.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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package schedule
import (
"sync"
"sync/atomic"
"time"
)
// Task holds information about the running task and can be used to stop running tasks.
type Task struct {
stop chan struct{}
nextExecution time.Time
startedAt time.Time
stopped int32 // 0 means active, 1 means stopped
once sync.Once
}
// newTask creates a new Task.
func newTask() *Task {
return &Task{
stop: make(chan struct{}),
startedAt: time.Now(),
}
}
// StartedAt returns the time when the scheduler was started.
func (s *Task) StartedAt() time.Time {
return s.startedAt
}
// NextExecutionTime returns the time when the next execution will happen.
func (s *Task) NextExecutionTime() time.Time {
return s.nextExecution
}
// ExecutesIn returns the duration until the next execution.
func (s *Task) ExecutesIn() time.Duration {
return time.Until(s.nextExecution)
}
// IsActive returns true if the scheduler is active.
func (s *Task) IsActive() bool {
return atomic.LoadInt32(&s.stopped) == 0
}
// Wait blocks until the scheduler is stopped.
// After and At will stop automatically after the task is executed.
func (s *Task) Wait() {
<-s.stop
}
// Stop stops the scheduler.
func (s *Task) Stop() {
s.once.Do(func() {
atomic.StoreInt32(&s.stopped, 1)
close(s.stop)
})
}
// After executes the task after the given duration.
// The function is non-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
func After(duration time.Duration, task func()) *Task {
scheduler := newTask()
scheduler.nextExecution = time.Now().Add(duration)
timer := time.NewTimer(duration)
go func() {
select {
case <-timer.C:
task()
scheduler.Stop()
case <-scheduler.stop:
// If the task is stopped before the timer fires, stop the timer.
if !timer.Stop() {
<-timer.C // drain if necessary
}
return
}
}()
return scheduler
}
// At executes the task at the given time.
// The function is non-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
func At(t time.Time, task func()) *Task {
scheduler := newTask()
scheduler.nextExecution = t
d := time.Until(t)
if d < 0 {
d = 0
}
timer := time.NewTimer(d)
go func() {
select {
case <-timer.C:
task()
scheduler.Stop()
case <-scheduler.stop:
if !timer.Stop() {
<-timer.C
}
return
}
}()
return scheduler
}
// Every executes the task in the given interval, as long as the task function returns true.
// The function is non-blocking. If you want to wait for the task to be executed, use the Task.Wait method.
func Every(interval time.Duration, task func() bool) *Task {
scheduler := newTask()
scheduler.nextExecution = time.Now().Add(interval)
ticker := time.NewTicker(interval)
go func() {
for {
select {
case <-ticker.C:
if !task() {
scheduler.Stop()
ticker.Stop()
return
}
scheduler.nextExecution = time.Now().Add(interval)
case <-scheduler.stop:
ticker.Stop()
return
}
}
}()
return scheduler
}