/
healthchecks.go
117 lines (95 loc) · 3.38 KB
/
healthchecks.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 resources
import (
"context"
"errors"
"net/http"
"time"
fthealth "github.com/Financial-Times/go-fthealth/v1_1"
"github.com/Financial-Times/service-status-go/gtg"
)
const panicGuideURL = "https://runbooks.in.ft.com/upp-notifications-push"
type RequestStatusFn func(ctx context.Context, url string) (int, error)
type KafkaConsumer interface {
ConnectivityCheck() error
}
type HealthCheck struct {
consumer KafkaConsumer
StatusFunc RequestStatusFn
apiGatewayGTGAddress string
}
func NewHealthCheck(kafkaConsumer KafkaConsumer, apiGatewayGTGAddress string, statusFunc RequestStatusFn) *HealthCheck {
return &HealthCheck{
consumer: kafkaConsumer,
apiGatewayGTGAddress: apiGatewayGTGAddress,
StatusFunc: statusFunc,
}
}
func (h *HealthCheck) Health() func(w http.ResponseWriter, r *http.Request) {
var checks []fthealth.Check
checks = append(checks, h.queueCheck())
checks = append(checks, h.apiGatewayCheck())
hc := fthealth.TimedHealthCheck{
HealthCheck: fthealth.HealthCheck{
SystemCode: "upp-notifications-push",
Name: "Notifications Push",
Description: "Checks if all the dependent services are reachable and healthy.",
Checks: checks,
},
Timeout: 10 * time.Second,
}
return fthealth.Handler(hc)
}
// Check is the the NotificationsPushHealthcheck method that checks if the kafka queue is available
func (h *HealthCheck) queueCheck() fthealth.Check {
return fthealth.Check{
ID: "message-queue-reachable",
Name: "MessageQueueReachable",
Severity: 1,
BusinessImpact: "Notifications about newly modified/published content will not reach this app, nor will they reach its clients.",
TechnicalSummary: "Message queue is not reachable/healthy",
PanicGuide: panicGuideURL,
Checker: h.checkAggregateMessageQueueReachable,
}
}
func (h *HealthCheck) GTG() gtg.Status {
if _, err := h.checkAggregateMessageQueueReachable(); err != nil {
return gtg.Status{GoodToGo: false, Message: err.Error()}
}
if _, err := h.checkAPIGatewayService(); err != nil {
return gtg.Status{GoodToGo: false, Message: err.Error()}
}
return gtg.Status{GoodToGo: true}
}
func (h *HealthCheck) checkAggregateMessageQueueReachable() (string, error) {
// ISSUE: consumer's helthcheck always returns true
err := h.consumer.ConnectivityCheck()
if err == nil {
return "Connectivity to kafka is OK.", nil
}
return "Error connecting to kafka", errors.New("error connecting to kafka queue")
}
// checks if apiGateway service is available
func (h *HealthCheck) apiGatewayCheck() fthealth.Check {
return fthealth.Check{
ID: "api-gateway-check",
Name: "ApiGatewayCheck",
Severity: 1,
BusinessImpact: "If apiGateway service is not available, consumer's helthcheck will return false ",
TechnicalSummary: "Checking if apiGateway service is available or not",
PanicGuide: panicGuideURL,
Checker: h.checkAPIGatewayService,
}
}
func (h *HealthCheck) checkAPIGatewayService() (string, error) {
if h.StatusFunc == nil {
return "", errors.New("no status func")
}
statusCode, err := h.StatusFunc(context.Background(), h.apiGatewayGTGAddress)
if err != nil {
return "", err
}
if statusCode == http.StatusOK {
return "ApiGateway service is working", nil
}
return "", errors.New("unable to verify ApiGateway service is working")
}