3abd0179 by astaxie

split into small files

1 parent ae376893
1 package grace
2
3 import "net"
4
5 type graceConn struct {
6 net.Conn
7 server *graceServer
8 }
9
10 func (c graceConn) Close() error {
11 c.server.wg.Done()
12 return c.Conn.Close()
13 }
1 package grace
2
3 import (
4 "net"
5 "os"
6 "syscall"
7 "time"
8 )
9
10 type graceListener struct {
11 net.Listener
12 stop chan error
13 stopped bool
14 server *graceServer
15 }
16
17 func newGraceListener(l net.Listener, srv *graceServer) (el *graceListener) {
18 el = &graceListener{
19 Listener: l,
20 stop: make(chan error),
21 server: srv,
22 }
23 go func() {
24 _ = <-el.stop
25 el.stopped = true
26 el.stop <- el.Listener.Close()
27 }()
28 return
29 }
30
31 func (gl *graceListener) Accept() (c net.Conn, err error) {
32 tc, err := gl.Listener.(*net.TCPListener).AcceptTCP()
33 if err != nil {
34 return
35 }
36
37 tc.SetKeepAlive(true)
38 tc.SetKeepAlivePeriod(3 * time.Minute)
39
40 c = graceConn{
41 Conn: tc,
42 server: gl.server,
43 }
44
45 gl.server.wg.Add(1)
46 return
47 }
48
49 func (el *graceListener) Close() error {
50 if el.stopped {
51 return syscall.EINVAL
52 }
53 el.stop <- nil
54 return <-el.stop
55 }
56
57 func (el *graceListener) File() *os.File {
58 // returns a dup(2) - FD_CLOEXEC flag *not* set
59 tl := el.Listener.(*net.TCPListener)
60 fl, _ := tl.File()
61 return fl
62 }
1 package grace
2
3 import (
4 "crypto/tls"
5 "fmt"
6 "log"
7 "net"
8 "net/http"
9 "os"
10 "os/exec"
11 "os/signal"
12 "strings"
13 "sync"
14 "syscall"
15 "time"
16 )
17
18 type graceServer struct {
19 *http.Server
20 GraceListener net.Listener
21 SignalHooks map[int]map[os.Signal][]func()
22 tlsInnerListener *graceListener
23 wg sync.WaitGroup
24 sigChan chan os.Signal
25 isChild bool
26 state uint8
27 Network string
28 }
29
30 // Serve accepts incoming connections on the Listener l,
31 // creating a new service goroutine for each.
32 // The service goroutines read requests and then call srv.Handler to reply to them.
33 func (srv *graceServer) Serve() (err error) {
34 srv.state = STATE_RUNNING
35 err = srv.Server.Serve(srv.GraceListener)
36 log.Println(syscall.Getpid(), "Waiting for connections to finish...")
37 srv.wg.Wait()
38 srv.state = STATE_TERMINATE
39 return
40 }
41
42 // ListenAndServe listens on the TCP network address srv.Addr and then calls Serve
43 // to handle requests on incoming connections. If srv.Addr is blank, ":http" is
44 // used.
45 func (srv *graceServer) ListenAndServe() (err error) {
46 addr := srv.Addr
47 if addr == "" {
48 addr = ":http"
49 }
50
51 go srv.handleSignals()
52
53 l, err := srv.getListener(addr)
54 if err != nil {
55 log.Println(err)
56 return err
57 }
58
59 srv.GraceListener = newGraceListener(l, srv)
60
61 if srv.isChild {
62 process, err := os.FindProcess(os.Getppid())
63 if err != nil {
64 log.Println(err)
65 return err
66 }
67 err = process.Kill()
68 if err != nil {
69 return err
70 }
71 }
72
73 log.Println(os.Getpid(), srv.Addr)
74 return srv.Serve()
75 }
76
77 // ListenAndServeTLS listens on the TCP network address srv.Addr and then calls
78 // Serve to handle requests on incoming TLS connections.
79 //
80 // Filenames containing a certificate and matching private key for the server must
81 // be provided. If the certificate is signed by a certificate authority, the
82 // certFile should be the concatenation of the server's certificate followed by the
83 // CA's certificate.
84 //
85 // If srv.Addr is blank, ":https" is used.
86 func (srv *graceServer) ListenAndServeTLS(certFile, keyFile string) (err error) {
87 addr := srv.Addr
88 if addr == "" {
89 addr = ":https"
90 }
91
92 config := &tls.Config{}
93 if srv.TLSConfig != nil {
94 *config = *srv.TLSConfig
95 }
96 if config.NextProtos == nil {
97 config.NextProtos = []string{"http/1.1"}
98 }
99
100 config.Certificates = make([]tls.Certificate, 1)
101 config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
102 if err != nil {
103 return
104 }
105
106 go srv.handleSignals()
107
108 l, err := srv.getListener(addr)
109 if err != nil {
110 log.Println(err)
111 return err
112 }
113
114 srv.tlsInnerListener = newGraceListener(l, srv)
115 srv.GraceListener = tls.NewListener(srv.tlsInnerListener, config)
116
117 if srv.isChild {
118 process, err := os.FindProcess(os.Getppid())
119 if err != nil {
120 log.Println(err)
121 return err
122 }
123 err = process.Kill()
124 if err != nil {
125 return err
126 }
127 }
128 log.Println(os.Getpid(), srv.Addr)
129 return srv.Serve()
130 }
131
132 // getListener either opens a new socket to listen on, or takes the acceptor socket
133 // it got passed when restarted.
134 func (srv *graceServer) getListener(laddr string) (l net.Listener, err error) {
135 if srv.isChild {
136 var ptrOffset uint = 0
137 if len(socketPtrOffsetMap) > 0 {
138 ptrOffset = socketPtrOffsetMap[laddr]
139 log.Println("laddr", laddr, "ptr offset", socketPtrOffsetMap[laddr])
140 }
141
142 f := os.NewFile(uintptr(3+ptrOffset), "")
143 l, err = net.FileListener(f)
144 if err != nil {
145 err = fmt.Errorf("net.FileListener error: %v", err)
146 return
147 }
148 } else {
149 l, err = net.Listen(srv.Network, laddr)
150 if err != nil {
151 err = fmt.Errorf("net.Listen error: %v", err)
152 return
153 }
154 }
155 return
156 }
157
158 // handleSignals listens for os Signals and calls any hooked in function that the
159 // user had registered with the signal.
160 func (srv *graceServer) handleSignals() {
161 var sig os.Signal
162
163 signal.Notify(
164 srv.sigChan,
165 syscall.SIGHUP,
166 syscall.SIGINT,
167 syscall.SIGTERM,
168 )
169
170 pid := syscall.Getpid()
171 for {
172 sig = <-srv.sigChan
173 srv.signalHooks(PRE_SIGNAL, sig)
174 switch sig {
175 case syscall.SIGHUP:
176 log.Println(pid, "Received SIGHUP. forking.")
177 err := srv.fork()
178 if err != nil {
179 log.Println("Fork err:", err)
180 }
181 case syscall.SIGINT:
182 log.Println(pid, "Received SIGINT.")
183 srv.shutdown()
184 case syscall.SIGTERM:
185 log.Println(pid, "Received SIGTERM.")
186 srv.shutdown()
187 default:
188 log.Printf("Received %v: nothing i care about...\n", sig)
189 }
190 srv.signalHooks(POST_SIGNAL, sig)
191 }
192 }
193
194 func (srv *graceServer) signalHooks(ppFlag int, sig os.Signal) {
195 if _, notSet := srv.SignalHooks[ppFlag][sig]; !notSet {
196 return
197 }
198 for _, f := range srv.SignalHooks[ppFlag][sig] {
199 f()
200 }
201 return
202 }
203
204 // shutdown closes the listener so that no new connections are accepted. it also
205 // starts a goroutine that will serverTimeout (stop all running requests) the server
206 // after DefaultTimeout.
207 func (srv *graceServer) shutdown() {
208 if srv.state != STATE_RUNNING {
209 return
210 }
211
212 srv.state = STATE_SHUTTING_DOWN
213 if DefaultTimeout >= 0 {
214 go srv.serverTimeout(DefaultTimeout)
215 }
216 err := srv.GraceListener.Close()
217 if err != nil {
218 log.Println(syscall.Getpid(), "Listener.Close() error:", err)
219 } else {
220 log.Println(syscall.Getpid(), srv.GraceListener.Addr(), "Listener closed.")
221 }
222 }
223
224 // serverTimeout forces the server to shutdown in a given timeout - whether it
225 // finished outstanding requests or not. if Read/WriteTimeout are not set or the
226 // max header size is very big a connection could hang
227 func (srv *graceServer) serverTimeout(d time.Duration) {
228 defer func() {
229 if r := recover(); r != nil {
230 log.Println("WaitGroup at 0", r)
231 }
232 }()
233 if srv.state != STATE_SHUTTING_DOWN {
234 return
235 }
236 time.Sleep(d)
237 log.Println("[STOP - Hammer Time] Forcefully shutting down parent")
238 for {
239 if srv.state == STATE_TERMINATE {
240 break
241 }
242 srv.wg.Done()
243 }
244 }
245
246 func (srv *graceServer) fork() (err error) {
247 regLock.Lock()
248 defer regLock.Unlock()
249 if runningServersForked {
250 return
251 }
252 runningServersForked = true
253
254 var files = make([]*os.File, len(runningServers))
255 var orderArgs = make([]string, len(runningServers))
256 for _, srvPtr := range runningServers {
257 switch srvPtr.GraceListener.(type) {
258 case *graceListener:
259 files[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.GraceListener.(*graceListener).File()
260 default:
261 files[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.tlsInnerListener.File()
262 }
263 orderArgs[socketPtrOffsetMap[srvPtr.Server.Addr]] = srvPtr.Server.Addr
264 }
265
266 log.Println(files)
267 path := os.Args[0]
268 var args []string
269 if len(os.Args) > 1 {
270 for _, arg := range os.Args[1:] {
271 if arg == "-graceful" {
272 break
273 }
274 args = append(args, arg)
275 }
276 }
277 args = append(args, "-graceful")
278 if len(runningServers) > 1 {
279 args = append(args, fmt.Sprintf(`-socketorder=%s`, strings.Join(orderArgs, ",")))
280 log.Println(args)
281 }
282 cmd := exec.Command(path, args...)
283 cmd.Stdout = os.Stdout
284 cmd.Stderr = os.Stderr
285 cmd.ExtraFiles = files
286 err = cmd.Start()
287 if err != nil {
288 log.Fatalf("Restart: Failed to launch, error: %v", err)
289 }
290
291 return
292 }
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!