-
Notifications
You must be signed in to change notification settings - Fork 0
/
graceful.go
114 lines (102 loc) · 3.22 KB
/
graceful.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
package graceful
import (
"context"
"fmt"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
const DefaultShutdownTimeout = 5 * time.Second
// A Server defines parameters for gracefully running an HTTP server.
// The zero value for Server is a valid configuration.
type Server struct {
*http.Server
// ShutdownTimeout is the maximum duration for shutting down the server.
// A zero or negative value means there will be no timeout.
ShutdownTimeout time.Duration
errChan chan error
}
// init server
func (s *Server) init() {
s.errChan = make(chan error, 1)
}
func (s *Server) load(opts []Option) {
for _, opt := range opts {
opt.apply(s)
}
}
// ListenAndServe listens on the TCP network address s.Addr and then
// calls s.Server.ListenAndServe to handle requests on incoming connections.
func (s *Server) ListenAndServe(opts ...Option) error {
s.init()
s.load(opts)
go func() {
if err := s.Server.ListenAndServe(); err != nil && err != http.ErrServerClosed {
s.errChan <- fmt.Errorf("[graceful] %w", err)
}
}()
return s.waitForShutdown()
}
// ListenAndServeTLS listens on the TCP network address srv.Addr and
// then calls ServeTLS to handle requests on incoming TLS connections.
// Accepted connections are configured to enable TCP keep-alives.
func (s *Server) ListenAndServeTLS(certFile, keyFile string, opts ...Option) error {
s.init()
s.load(opts)
go func() {
if err := s.Server.ListenAndServeTLS(certFile, keyFile); err != nil && err != http.ErrServerClosed {
s.errChan <- fmt.Errorf("[graceful] %w", err)
}
}()
return s.waitForShutdown()
}
// waiting for shutdown or error occur.
func (s *Server) waitForShutdown() error {
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
select {
case err := <-s.errChan:
return err
case <-quit:
}
ctx, cancel := context.WithTimeout(context.Background(), s.ShutdownTimeout)
defer cancel()
if err := s.Server.Shutdown(ctx); err != nil {
return err
}
return nil
}
// ListenAndServe listens on the TCP network address addr and then calls
// Serve with handler to handle requests on incoming connections.
// Accepted connections are configured to enable TCP keep-alives.
//
// The handler is typically nil, in which case the DefaultServeMux is used.
// ShutdownTimeout defaults 5 seconds.
func ListenAndServe(addr string, handler http.Handler, opts ...Option) error {
server := &Server{
Server: &http.Server{
Addr: addr,
Handler: handler,
},
ShutdownTimeout: DefaultShutdownTimeout,
}
return server.ListenAndServe(opts...)
}
// ListenAndServeTLS acts identically to ListenAndServe, except that it
// expects HTTPS connections. Additionally, files containing a certificate and
// matching private key for the server must be provided. If the certificate
// is signed by a certificate authority, the certFile should be the concatenation
// of the server's certificate, any intermediates, and the CA's certificate.
// ShutdownTimeout defaults 5 seconds.
func ListenAndServeTLS(addr, certFile, keyFile string, handler http.Handler, opts ...Option) error {
server := &Server{
Server: &http.Server{
Addr: addr,
Handler: handler,
},
ShutdownTimeout: DefaultShutdownTimeout,
}
return server.ListenAndServeTLS(certFile, keyFile, opts...)
}