-
Notifications
You must be signed in to change notification settings - Fork 0
/
grace.go
143 lines (119 loc) · 3.02 KB
/
grace.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
// Package grace provides a easy way to graceful restart or
// shutdown http server,compatible with systemd and supervisor.
package grace
import (
"errors"
"net/http"
"os"
"syscall"
"time"
)
type Grace interface {
ListenAndServe(addr string, handler http.Handler, opt ...Option) error
}
// env constants
const (
EnvWorker = "GracefulWorker"
EnvFdNum = "GracefulFdNum"
EnvOldWorkerPid = "GracefulOldWorkerPid"
ValWorker = "ValueWorker"
)
// default option value
var defaultOption = &option{
restartSignal: []syscall.Signal{syscall.SIGUSR1},
shutdownSignal: []syscall.Signal{syscall.SIGTERM, syscall.SIGINT},
pulseInterval: time.Second,
shutdownTimeout: 60 * time.Second,
}
// http server
type Server struct {
opt *option
addrs []string
handlers []http.Handler
}
func NewServer(opt ...Option) *Server {
option := defaultOption
for _, opt := range opt {
opt(option)
}
return &Server{
addrs: make([]string, 0),
handlers: make([]http.Handler, 0),
opt: option,
}
}
// http listenAndServe
func ListenAndServe(addr string, handler http.Handler, opt ...Option) error {
server := NewServer(opt...)
return server.ListenAndServe(addr, handler)
}
// grace goroutine, wait all goroutine return.
func Go(f func()) {
go func() {
wg.Add(1)
defer wg.Done()
f()
}()
}
// Run run all register server
func (s *Server) Run() error {
if len(s.addrs) == 0 {
return errors.New("no servers")
}
if IsWorker() {
worker := &worker{handlers: s.handlers, opt: s.opt, shutdownCh: make(chan struct{})}
return worker.run()
}
if IsMaster() {
master := &master{addrs: s.addrs, opt: s.opt, workerExit: make(chan error)}
return master.run()
}
return errors.New("unknown server")
}
// Register regist a pair of addr and router.
func (s *Server) Register(addr string, handler http.Handler) {
s.addrs = append(s.addrs, addr)
s.handlers = append(s.handlers, handler)
}
func (s *Server) ListenAndServe(addr string, handler http.Handler) error {
s.Register(addr, handler)
return s.Run()
}
func IsWorker() bool {
return os.Getenv(EnvWorker) == ValWorker
}
func IsMaster() bool {
return !IsWorker()
}
// user-defined option
type option struct {
restartSignal []syscall.Signal
shutdownSignal []syscall.Signal
pulseInterval time.Duration
shutdownTimeout time.Duration
}
type Option func(o *option)
// RestartSignal set restart signal, otherwise use default value.
func RestartSignal(sigs []syscall.Signal) Option {
return func(o *option) {
o.restartSignal = sigs
}
}
// ShutdownSignal set shutdown signal, otherwise use default value.
func ShutdownSignal(sigs []syscall.Signal) Option {
return func(o *option) {
o.shutdownSignal = sigs
}
}
// PulseInterval set pulse interval, otherwise use default value.
func PulseInterval(pulse time.Duration) Option {
return func(o *option) {
o.pulseInterval = pulse
}
}
// ShutdownTimeout set shutdown timeout, otherwise use default value.
func ShutdownTimeout(timeout time.Duration) Option {
return func(o *option) {
o.shutdownTimeout = timeout
}
}