-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.go
117 lines (99 loc) · 2.71 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
package main
import (
"fmt"
"github.com/labstack/echo/v4"
"github.com/labstack/echo/v4/middleware"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
port := getEnvDefault("PORT", "8080")
healthcheckPath := getEnvDefault("HEALTHCHECK_PATH", "/healthz")
terminationDelay := getEnvDurationDefault("TERMINATION_DELAY", time.Second*120)
upstreamPort := requireEnv("UPSTREAM_PORT")
upstreamHealthcheckPath := requireEnv("UPSTREAM_HEALTHCHECK_PATH")
upstreamTimeout := requireEnvDuration("UPSTREAM_TIMEOUT")
upstreamHealth := fmt.Sprintf("http://localhost:%s%s", upstreamPort, upstreamHealthcheckPath)
e := echo.New()
e.HideBanner = true
e.Use(middleware.Logger())
e.Use(middleware.Recover())
signals := make(chan os.Signal, 1)
done := make(chan bool, 1)
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM)
terminating := false
go func() {
sig := <-signals
log.Printf("caught signal %s", sig)
log.Print("will return unhealthy response")
terminating = true
log.Printf("terminating in %v", terminationDelay)
time.Sleep(terminationDelay)
done <- true
}()
e.GET(healthcheckPath, func(c echo.Context) error {
if terminating {
return c.String(http.StatusServiceUnavailable, "terminating")
}
client := http.Client{
Timeout: upstreamTimeout,
}
log.Printf("checking upstream health at %s", upstreamHealth)
res, err := client.Get(upstreamHealth)
if err != nil {
log.Print("failed to call upstream")
return c.String(http.StatusServiceUnavailable, "upstream service is not available")
}
if res.StatusCode >= http.StatusInternalServerError {
log.Printf("upstream returned error: %d", res.StatusCode)
return c.String(http.StatusServiceUnavailable, "upstream service is returning error")
}
log.Print("upstream is healthy")
return c.String(http.StatusOK, "OK")
})
go func() {
log.Fatal(e.Start(":" + port))
}()
<-done
}
func getEnvDurationDefault(name string, defaultValue time.Duration) time.Duration {
value, ok := os.LookupEnv(name)
if !ok {
return defaultValue
}
duration, err := time.ParseDuration(value)
if err != nil {
log.Printf("error parsing %s: %s", name, err)
return defaultValue
}
return duration
}
func getEnvDefault(name string, defaultValue string) string {
value, ok := os.LookupEnv(name)
if !ok {
return defaultValue
}
return value
}
func requireEnv(name string) string {
value, ok := os.LookupEnv(name)
if !ok {
log.Fatalf("%s is not set", name)
}
return value
}
func requireEnvDuration(name string) time.Duration {
value, ok := os.LookupEnv(name)
if !ok {
log.Fatalf("%s is not set", name)
}
duration, err := time.ParseDuration(value)
if err != nil {
log.Fatalf("error parsing %s: %s", name, err)
}
return duration
}