/
gtimer_entry.go
133 lines (117 loc) · 3.19 KB
/
gtimer_entry.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
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gtimer
import (
"github.com/gogf/gf/container/gtype"
)
// Entry is the timing job.
type Entry struct {
job JobFunc // The job function.
timer *Timer // Belonged timer.
ticks int64 // The job runs every tick.
times *gtype.Int // Limit running times.
status *gtype.Int // Job status.
singleton *gtype.Bool // Singleton mode.
nextTicks *gtype.Int64 // Next run ticks of the job.
infinite *gtype.Bool // No times limit.
}
// JobFunc is the job function.
type JobFunc = func()
// Status returns the status of the job.
func (entry *Entry) Status() int {
return entry.status.Val()
}
// Run runs the timer job asynchronously.
func (entry *Entry) Run() {
if !entry.infinite.Val() {
leftRunningTimes := entry.times.Add(-1)
// It checks its running times exceeding.
if leftRunningTimes < 0 {
entry.status.Set(StatusClosed)
return
}
}
go func() {
defer func() {
if err := recover(); err != nil {
if err != panicExit {
panic(err)
} else {
entry.Close()
return
}
}
if entry.Status() == StatusRunning {
entry.SetStatus(StatusReady)
}
}()
entry.job()
}()
}
// doCheckAndRunByTicks checks the if job can run in given timer ticks,
// it runs asynchronously if the given `currentTimerTicks` meets or else
// it increments its ticks and waits for next running check.
func (entry *Entry) doCheckAndRunByTicks(currentTimerTicks int64) {
// Ticks check.
if currentTimerTicks < entry.nextTicks.Val() {
return
}
entry.nextTicks.Set(currentTimerTicks + entry.ticks)
// Perform job checking.
switch entry.status.Val() {
case StatusRunning:
if entry.IsSingleton() {
return
}
case StatusReady:
if !entry.status.Cas(StatusReady, StatusRunning) {
return
}
case StatusStopped:
return
case StatusClosed:
return
}
// Perform job running.
entry.Run()
}
// SetStatus custom sets the status for the job.
func (entry *Entry) SetStatus(status int) int {
return entry.status.Set(status)
}
// Start starts the job.
func (entry *Entry) Start() {
entry.status.Set(StatusReady)
}
// Stop stops the job.
func (entry *Entry) Stop() {
entry.status.Set(StatusStopped)
}
// Close closes the job, and then it will be removed from the timer.
func (entry *Entry) Close() {
entry.status.Set(StatusClosed)
}
// Reset resets the job, which resets its ticks for next running.
func (entry *Entry) Reset() {
entry.nextTicks.Set(entry.timer.ticks.Val() + entry.ticks)
}
// IsSingleton checks and returns whether the job in singleton mode.
func (entry *Entry) IsSingleton() bool {
return entry.singleton.Val()
}
// SetSingleton sets the job singleton mode.
func (entry *Entry) SetSingleton(enabled bool) {
entry.singleton.Set(enabled)
}
// Job returns the job function of this job.
func (entry *Entry) Job() JobFunc {
return entry.job
}
// SetTimes sets the limit running times for the job.
func (entry *Entry) SetTimes(times int) {
entry.times.Set(times)
entry.infinite.Set(false)
}