-
Notifications
You must be signed in to change notification settings - Fork 0
/
exit_ctrl.go
154 lines (128 loc) · 2.61 KB
/
exit_ctrl.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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package exitctrl
import (
"context"
"os"
"os/signal"
"syscall"
"time"
"github.com/golang/glog"
)
// prestop interval
var gs_PreStop = 10 * time.Second
// the context to be notified to exit
var SignalCtx context.Context = nil
var gs_ExitChan chan os.Signal = nil
type ExitController struct {
NotifyFlag bool // the flag to notify to exit
JustExitFlag bool // exit flag
CancelFn context.CancelFunc // context cancel function
}
var gs_Controller = ExitController{
NotifyFlag: false,
JustExitFlag: false,
CancelFn: nil,
}
// register to process the exit signal
func Register() error {
RegisterWithDuration(0)
return nil
}
func RegisterWithDuration(duration time.Duration) error {
// reset the state
gs_PreStop = duration
gs_Controller.NotifyFlag = false
gs_Controller.JustExitFlag = false
SignalCtx, gs_Controller.CancelFn = context.WithCancel(context.Background())
// register the signal
gs_ExitChan = make(chan os.Signal, 1)
signal.Notify(
gs_ExitChan,
syscall.SIGHUP,
syscall.SIGINT,
syscall.SIGQUIT,
syscall.SIGTERM,
)
// listen
go listenToSignal()
return nil
}
// notify the routines to exit
func NotifyToExit() {
gs_ExitChan <- os.Interrupt
gs_Controller.NotifyFlag = true
}
// check if the caller need to exit
func IfNeedToExit() bool {
return gs_Controller.NotifyFlag
}
// wait for the exit signal
func WaitForSignal(interval time.Duration) bool {
now := time.Now()
for {
select {
case <-SignalCtx.Done():
return true
default:
if time.Since(now) >= interval {
return false
}
time.Sleep(10 * time.Millisecond)
}
}
}
type ExitRoutine func()
func AddExitRoutine(r ExitRoutine) {
go func() {
for {
if WaitForSignal(500 * time.Millisecond) {
r()
return
}
}
}()
}
// main wait loop
func Join() {
// wait for the exit signal
for {
if WaitForSignal(500 * time.Millisecond) {
break
}
}
// prestop
Prestop()
}
// prestop function
func Prestop() {
for {
if gs_Controller.JustExitFlag {
return
}
time.Sleep(100 * time.Millisecond)
}
}
// register the signal and listen
func listenToSignal() {
// wait for the signal
for s := range gs_ExitChan {
glog.Warning("get a signal: ", s)
switch s {
case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
glog.Warning("to exit")
clean()
glog.Warning("exited")
return
default:
glog.Warning("unknown signal: ", s)
}
}
}
// perform the clean operation
func clean() {
// set the notify flag
gs_Controller.NotifyFlag = true
gs_Controller.CancelFn()
// prestop
time.Sleep(gs_PreStop)
gs_Controller.JustExitFlag = true
}