-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.go
120 lines (106 loc) · 2.21 KB
/
server.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
// SPDX-License-Identifier: MIT
//
// Copyright 2021 Andrew Bursavich. All rights reserved.
// Use of this source code is governed by The MIT License
// which can be found in the LICENSE file.
// Package graceful runs processes, such as servers, with graceful shutdown.
package graceful
import (
"context"
"net"
"net/http"
"sync"
)
// HTTPServerProcess converts a net.Listener and http.Server into a graceful.Process.
func HTTPServerProcess(lis net.Listener, srv *http.Server) Process {
return &httpServer{srv, lis}
}
type httpServer struct {
srv *http.Server
lis net.Listener
}
func (s *httpServer) Run(ctx context.Context) error {
done := make(chan struct{})
defer close(done)
go func() {
select {
case <-done:
case <-ctx.Done():
_ = s.srv.Close()
}
}()
if err := s.srv.Serve(s.lis); err != http.ErrServerClosed {
return err
}
return nil
}
func (s *httpServer) Shutdown(ctx context.Context) error {
s.srv.SetKeepAlivesEnabled(false)
return s.srv.Shutdown(ctx)
}
// A GRPCServer is an interface for a grpc.Server.
type GRPCServer interface {
Serve(net.Listener) error
GracefulStop()
Stop()
}
type grpcServer struct {
srv GRPCServer
lis net.Listener
once sync.Once
errCh chan error
done chan struct{}
err error
}
// GRPCServerProcess converts a net.Listener and grpc.Server into a graceful.Process.
func GRPCServerProcess(lis net.Listener, srv GRPCServer) Process {
return &grpcServer{
srv: srv,
lis: lis,
errCh: make(chan error),
done: make(chan struct{}),
}
}
func (s *grpcServer) Run(ctx context.Context) error {
done := make(chan struct{})
defer close(done)
go func() {
select {
case <-done:
case <-ctx.Done():
_ = s.Shutdown(ctx)
}
}()
return s.srv.Serve(s.lis)
}
func (s *grpcServer) Shutdown(ctx context.Context) error {
s.once.Do(func() { go s.shutdown() })
select {
case <-s.done:
return s.err
case <-ctx.Done():
}
select {
case <-s.done:
return s.err
case s.errCh <- ctx.Err():
}
<-s.done
return s.err
}
func (s *grpcServer) shutdown() {
defer close(s.done)
done := make(chan struct{})
go func() {
defer close(done)
s.srv.GracefulStop()
}()
select {
case <-done:
return
case err := <-s.errCh:
s.err = err
s.srv.Stop()
<-done
}
}