-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.go
executable file
·142 lines (118 loc) · 3.05 KB
/
main.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
package main
import (
"context"
"errors"
"fmt"
"net/http"
"os"
"os/signal"
"sync"
"syscall"
"time"
"golang.org/x/sync/errgroup"
)
var Interrupt = errors.New("caught interrupt signal")
func main() {
ctx := context.Background()
g, _ := errgroup.WithContext(context.Background())
// api server
var apiServer http.Server
// healthz server
var healthzServer http.Server
// interrupt goroutine exit after receive message from this channel
interruptQuit := make(chan struct{})
var closeOnce sync.Once
shutdownApiServer := func() {
// wait 30s for server shutdown
shutdownCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
err := apiServer.Shutdown(shutdownCtx)
if err != nil {
fmt.Printf("fail to shutdown api server: %v\n", err)
}
}
shutdownHealthzServer := func() {
// wait 30s for server shutdown
shutdownCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
err := healthzServer.Shutdown(shutdownCtx)
if err != nil {
fmt.Printf("fail to shutdown api server: %v\n", err)
}
}
// api server goroutine
{
apiMux := http.NewServeMux()
apiMux.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "hello world")
})
apiServerAddr := ":8080"
apiServer = http.Server{
Addr: apiServerAddr,
Handler: apiMux,
}
g.Go(func() error {
fmt.Printf("start api server on %s\n", apiServerAddr)
err := apiServer.ListenAndServe()
// notify healthz server goroutine shutdown
shutdownHealthzServer()
// notify interrupt goroutine shutdown
closeOnce.Do(func() {
close(interruptQuit)
})
fmt.Printf("api server goroutine exit\n")
return err
})
}
// healthz server goroutine
{
healthzMux := http.NewServeMux()
healthzMux.HandleFunc("/healthz", func(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "ok")
})
healthzServerAddr := ":8081"
healthzServer = http.Server{
Addr: healthzServerAddr,
Handler: healthzMux,
}
g.Go(func() error {
fmt.Printf("start healthz server on %s\n", healthzServerAddr)
err := healthzServer.ListenAndServe()
// notify api server goroutine shutdown
shutdownApiServer()
// notify interrupt goroutine shutdown
closeOnce.Do(func() {
close(interruptQuit)
})
fmt.Printf("healthz server goroutine exit\n")
return err
})
}
// interrupt goroutine
{
g.Go(func() error {
c := make(chan os.Signal)
signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
for {
select {
case s := <-c:
fmt.Printf("program receive signal '%v'\n", s)
// shutdown api server after signal received
shutdownApiServer()
// shutdown healthz server after signal received
shutdownHealthzServer()
fmt.Printf("interrupt goroutine exit\n")
return Interrupt
case <-interruptQuit:
// return after channel closed
fmt.Printf("interrupt goroutine exit\n")
return nil
}
}
})
}
if err := g.Wait(); err != nil {
fmt.Printf("errgroup done with error %v\n", err)
}
fmt.Printf("program exit\n")
}