-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhealth.go
150 lines (124 loc) · 3.88 KB
/
health.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
143
144
145
146
147
148
149
150
package notella
import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
_ "net/http/pprof"
"firebase.google.com/go/v4/messaging"
ll "github.com/gwennlbh/label-logger-go"
"github.com/nats-io/nats.go"
"github.com/nats-io/nats.go/jetstream"
)
type HealthResponse struct {
Redis bool `json:"redis"`
NATS bool `json:"nats"`
ChurrosDatabase bool `json:"churros_db"`
Firebase bool `json:"firebase"`
}
func (r HealthResponse) AllGood() bool {
return r.Redis && r.NATS && r.ChurrosDatabase && r.Firebase
}
func healthHandler(w http.ResponseWriter, r *http.Request) {
ll.Debug("Checking health due to request from %s", r.RemoteAddr)
// Set the content type to JSON
w.Header().Set("Content-Type", "application/json")
// Example response (you can modify this with your own business logic)
response := CheckHealth()
// Marshal the response to JSON and write it to the response writer
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, "Unable to encode JSON", http.StatusInternalServerError)
return
}
}
func CheckHealth() HealthResponse {
response := HealthResponse{}
if err := CheckRedisHealth(); err != nil {
ll.ErrorDisplay("while checking Redis health", err)
} else {
response.Redis = true
}
if err := CheckNATSHealth(); err != nil {
ll.ErrorDisplay("while checking NATS health", err)
} else {
response.NATS = true
}
if err := CheckChurrosDatabaseHealth(); err != nil {
ll.ErrorDisplay("while checking Churros database health", err)
} else {
response.ChurrosDatabase = true
}
if err := CheckFirebaseHealth(); err != nil {
ll.ErrorDisplay("while checking Firebase Cloud Messaging health", err)
} else {
response.Firebase = true
}
return response
}
func StartHealthCheckEndpoint(port int) {
// Set up route for the /health endpoint
http.HandleFunc("/health", healthHandler)
// Start the server and log any errors
ll.Log("Starting", "cyan", "health check endpoint on :%d/health", port)
if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
log.Fatalf("Server failed to start: %v", err)
}
}
func CheckRedisHealth() error {
return redisClient.Ping(context.Background()).Err()
}
func CheckNATSHealth() error {
nc, err := nats.Connect(config.NatsURL)
if err != nil {
return fmt.Errorf("could not connect to NATS at %s: %w", config.NatsURL, err)
}
defer nc.Close()
js, err := jetstream.New(nc)
if err != nil {
return fmt.Errorf("could not connect to Jetstream: %w", err)
}
stream, err := js.CreateStream(context.Background(), jetstream.StreamConfig{
Name: StreamName,
Subjects: []string{SubjectName},
})
if err != nil {
return fmt.Errorf("could not create stream: %w", err)
}
consumers := stream.ListConsumers(context.Background())
if consumers.Err() != nil {
return fmt.Errorf("could not list consumers: %w", consumers.Err())
}
for info := range consumers.Info() {
if consumers.Err() != nil {
return fmt.Errorf("could not get consumer info: %w", consumers.Err())
}
if info.Name == ConsumerName {
return nil
}
}
return fmt.Errorf("%s not connected to stream", ConsumerName)
}
func CheckChurrosDatabaseHealth() error {
return prisma.Prisma.QueryRaw("SELECT 1").Exec(context.Background(), nil)
}
func CheckFirebaseHealth() error {
if !config.HasValidFirebaseServiceAccount() {
return nil
}
fcm, err := firebaseClient.Messaging(firebaseCtx)
if err != nil {
return fmt.Errorf("while initializing messaging client: %w", err)
}
_, err = fcm.SendDryRun(firebaseCtx, &messaging.Message{
Notification: &messaging.Notification{
Title: "Health check attempt",
Body: "This is a health check attempt to ensure that the FCM service is working properly. The notification is not supposed to be displayed to the user.",
},
Token: "invalid",
})
if err != nil && err.Error() == "The registration token is not a valid FCM registration token" {
return nil
}
return err
}