-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshutdown.go
87 lines (69 loc) · 2.17 KB
/
shutdown.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
package easyshutdown
import (
"context"
"log"
"net/http"
"os"
"time"
opentrace "go.opentelemetry.io/otel/sdk/trace"
"google.golang.org/grpc"
)
const (
// Kubernetes (rolling update) doesn't wait until a pod is out of rotation before sending SIGTERM,
// and external LB could still route traffic to a non-existing pod resulting in a surge of 50x API errors.
// It's recommended to wait for a while before terminating the program; see for details:
// https://github.com/kubernetes-retired/contrib/issues/1140.
preShutdownDelay = 3 * time.Second
defaultTimeoutDuration = 3 * time.Second
)
type supportedServices struct {
httpServer *http.Server
httpsServer *http.Server
grpcServer *grpc.Server
tracerProvider *opentrace.TracerProvider
}
type Shutdown struct {
logger *log.Logger
shutdownTimeout time.Duration
services *supportedServices
}
func NewShutdown(options ...Option) (*Shutdown, error) {
srv := &Shutdown{
shutdownTimeout: defaultTimeoutDuration,
logger: log.New(os.Stderr, "easyshutdown ", log.LstdFlags),
services: &supportedServices{},
}
for _, o := range options {
o(srv)
}
return srv, nil
}
func (s *Shutdown) Graceful() {
stopCh := signals()
<-stopCh
ctx, cancel := context.WithTimeout(context.Background(), s.shutdownTimeout)
defer cancel()
s.logger.Println("Shutting down HTTP/HTTPS server")
// Wait for Kubernetes readiness probe to remove this instance from the LB.
time.Sleep(preShutdownDelay)
// stop OpenTelemetry tracer provider
if s.services.tracerProvider != nil {
if err := s.services.tracerProvider.Shutdown(ctx); err != nil {
s.logger.Printf("stopping tracer provider: failed: %s", err.Error())
}
}
if s.services.grpcServer != nil {
s.logger.Println("Shutting down GRPC server")
s.services.grpcServer.GracefulStop()
}
if s.services.httpServer != nil {
if err := s.services.httpServer.Shutdown(ctx); err != nil {
s.logger.Printf("HTTP server graceful shutdown: failed: %s", err.Error())
}
}
if s.services.httpsServer != nil {
if err := s.services.httpsServer.Shutdown(ctx); err != nil {
s.logger.Printf("HTTPS server graceful shutdown: failed: %s", err.Error())
}
}
}