This repository has been archived by the owner on Jan 18, 2023. It is now read-only.
forked from facebookarchive/grace
-
Notifications
You must be signed in to change notification settings - Fork 3
/
http.go
156 lines (138 loc) · 3.98 KB
/
http.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
155
156
// Package gracehttp provides easy to use graceful restart
// functionality for HTTP server.
package gracehttp
import (
"bytes"
"crypto/tls"
"errors"
"flag"
"fmt"
"log"
"net"
"net/http"
"os"
"github.com/Shopify/go.grace"
)
var (
verbose = flag.Bool("gracehttp.log", true, "Enable logging.")
errListenersCount = errors.New("unexpected listeners count")
errNoStartedListeners = errors.New("no started listeners")
)
// An App contains one or more servers and associated configuration.
type App struct {
Servers []*http.Server
listeners []grace.Listener
errors chan error
}
// Listen will inherit or create new listeners. Returns a bool indicating if we
// inherited listeners. This return value is useful in order to decide if we
// should instruct the parent process to terminate.
func (a *App) Listen() (bool, error) {
var err error
a.errors = make(chan error, len(a.Servers))
a.listeners, err = grace.Inherit()
if err == nil {
if len(a.Servers) != len(a.listeners) {
return true, errListenersCount
}
return true, nil
} else if err == grace.ErrNotInheriting {
if a.listeners, err = a.newListeners(); err != nil {
return false, err
}
return false, nil
}
return false, fmt.Errorf("failed graceful handoff: %s", err)
}
// Creates new listeners (as in not inheriting) for all the configured Servers.
func (a *App) newListeners() ([]grace.Listener, error) {
listeners := make([]grace.Listener, len(a.Servers))
for index, server := range a.Servers {
addr, err := net.ResolveTCPAddr("tcp", server.Addr)
if err != nil {
return nil, fmt.Errorf("net.ResolveTCPAddr %s: %s", server.Addr, err)
}
l, err := net.ListenTCP("tcp", addr)
if err != nil {
return nil, fmt.Errorf("net.ListenTCP %s: %s", server.Addr, err)
}
listeners[index] = grace.NewListener(l)
}
return listeners, nil
}
// Serve the configured servers, but do not block. You must call Wait at some
// point to ensure correctly waiting for graceful termination.
func (a *App) Serve() {
for i, l := range a.listeners {
go func(i int, l net.Listener) {
server := a.Servers[i]
// Wrap the listener for TLS support if necessary.
if server.TLSConfig != nil {
l = tls.NewListener(l, server.TLSConfig)
}
err := server.Serve(l)
// The underlying Accept() will return grace.ErrAlreadyClosed
// when a signal to do the same is returned, which we are okay with.
if err != nil && err != grace.ErrAlreadyClosed {
a.errors <- fmt.Errorf("http.Serve: %s", err)
}
}(i, l)
}
}
// Wait for the serving goroutines to finish.
func (a *App) Wait() error {
waiterr := make(chan error)
go func() { waiterr <- grace.Wait(a.listeners) }()
select {
case err := <-waiterr:
return err
case err := <-a.errors:
return err
}
}
// Serve will serve the given http.Servers and will monitor for signals
// allowing for graceful termination (SIGTERM) or restart (SIGUSR2).
func Serve(servers ...*http.Server) error {
app := &App{Servers: servers}
inherited, err := app.Listen()
if err != nil {
return err
}
if *verbose {
if inherited {
ppid := os.Getppid()
if ppid == 1 {
log.Printf("Listening on init activated %s", pprintAddr(app.listeners))
} else {
const msg = "Graceful handoff of %s with new pid %d and old pid %d"
log.Printf(msg, pprintAddr(app.listeners), os.Getpid(), ppid)
}
} else {
const msg = "Serving %s with pid %d"
log.Printf(msg, pprintAddr(app.listeners), os.Getpid())
}
}
app.Serve()
// Close the parent if we inherited and it wasn't init that started us.
if inherited && os.Getppid() != 1 {
if err := grace.CloseParent(); err != nil {
return fmt.Errorf("failed to close parent: %s", err)
}
}
err = app.Wait()
if *verbose {
log.Printf("Exiting pid %d.", os.Getpid())
}
return err
}
// Used for pretty printing addresses.
func pprintAddr(listeners []grace.Listener) []byte {
out := bytes.NewBuffer(nil)
for i, l := range listeners {
if i != 0 {
fmt.Fprint(out, ", ")
}
fmt.Fprint(out, l.Addr())
}
return out.Bytes()
}