forked from gitter-badger/api-3
-
Notifications
You must be signed in to change notification settings - Fork 11
/
serve13.go
75 lines (65 loc) · 2.26 KB
/
serve13.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
// +build go1.3
package graceful
import (
"log"
"net"
"net/http"
"github.com/zenazn/goji/graceful/listener"
)
// This is a slightly hacky shim to disable keepalives when shutting a server
// down. We could have added extra functionality in listener or signal.go to
// deal with this case, but this seems simpler.
type gracefulServer struct {
net.Listener
s *http.Server
}
func (g gracefulServer) Close() error {
g.s.SetKeepAlivesEnabled(false)
return g.Listener.Close()
}
// A chaining http.ConnState wrapper
type connState func(net.Conn, http.ConnState)
func (c connState) Wrap(nc net.Conn, s http.ConnState) {
// There are a few other states defined, most notably StateActive.
// Unfortunately it doesn't look like it's possible to make use of
// StateActive to implement graceful shutdown, since StateActive is set
// after a complete request has been read off the wire with an intent to
// process it. If we were to race a graceful shutdown against a
// connection that was just read off the wire (but not yet in
// StateActive), we would accidentally close the connection out from
// underneath an active request.
//
// We already needed to work around this for Go 1.2 by shimming out a
// full net.Conn object, so we can just fall back to the old behavior
// there.
//
// I started a golang-nuts thread about this here:
// https://groups.google.com/forum/#!topic/golang-nuts/Xi8yjBGWfCQ
// I'd be very eager to find a better way to do this, so reach out to me
// if you have any ideas.
switch s {
case http.StateIdle:
if err := listener.MarkIdle(nc); err != nil {
log.Printf("error marking conn as idle: %v", err)
}
case http.StateHijacked:
if err := listener.Disown(nc); err != nil {
log.Printf("error disowning hijacked conn: %v", err)
}
}
if c != nil {
c(nc, s)
}
}
func (srv *Server) Serve(l net.Listener) error {
// Spawn a shadow http.Server to do the actual servering. We do this
// because we need to sketch on some of the parameters you passed in,
// and it's nice to keep our sketching to ourselves.
shadow := *(*http.Server)(srv)
shadow.ConnState = connState(shadow.ConnState).Wrap
l = gracefulServer{l, &shadow}
wrap := listener.Wrap(l, listener.Automatic)
appendListener(wrap)
err := shadow.Serve(wrap)
return peacefulError(err)
}