This repository has no description
1package notella
2
3import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "log"
8 "net/http"
9
10 "firebase.google.com/go/v4/messaging"
11 ll "github.com/gwennlbh/label-logger-go"
12 "github.com/nats-io/nats.go"
13)
14
15type HealthResponse struct {
16 Redis bool `json:"redis"`
17 NATS bool `json:"nats"`
18 ChurrosDatabase bool `json:"churros_db"`
19 Firebase bool `json:"firebase"`
20}
21
22func healthHandler(w http.ResponseWriter, r *http.Request) {
23 ll.Debug("Checking health due to request from %s", r.RemoteAddr)
24 // Set the content type to JSON
25 w.Header().Set("Content-Type", "application/json")
26
27 // Example response (you can modify this with your own business logic)
28 response := HealthResponse{}
29
30 if err := CheckRedisHealth(); err != nil {
31 ll.ErrorDisplay("while checking Redis health", err)
32 } else {
33 response.Redis = true
34 }
35
36 if err := CheckNATSHealth(); err != nil {
37 ll.ErrorDisplay("while checking NATS health", err)
38 } else {
39 response.NATS = true
40 }
41
42 if err := CheckChurrosDatabaseHealth(); err != nil {
43 ll.ErrorDisplay("while checking Churros database health", err)
44 } else {
45 response.ChurrosDatabase = true
46 }
47
48 if err := CheckFirebaseHealth(); err != nil {
49 ll.ErrorDisplay("while checking Firebase Cloud Messaging health", err)
50 } else {
51 response.Firebase = true
52 }
53
54 // Marshal the response to JSON and write it to the response writer
55 if err := json.NewEncoder(w).Encode(response); err != nil {
56 http.Error(w, "Unable to encode JSON", http.StatusInternalServerError)
57 return
58 }
59}
60
61func StartHealthCheckEndpoint(port int) {
62 // Set up route for the /health endpoint
63 http.HandleFunc("/health", healthHandler)
64
65 // Start the server and log any errors
66 ll.Log("Starting", "cyan", "health check endpoint on :%d/health", port)
67 if err := http.ListenAndServe(fmt.Sprintf(":%d", port), nil); err != nil {
68 log.Fatalf("Server failed to start: %v", err)
69 }
70}
71
72func CheckRedisHealth() error {
73 return redisClient.Ping(context.Background()).Err()
74}
75
76func CheckNATSHealth() error {
77 nc, err := nats.Connect(config.NatsURL)
78 if err != nil {
79 return fmt.Errorf("could not connect to NATS at %s: %w", config.NatsURL, err)
80 }
81
82 _, err = nc.JetStream()
83 if err != nil {
84 return fmt.Errorf("could not connect to Jetstream: %w", err)
85 }
86
87 return nil
88}
89
90func CheckChurrosDatabaseHealth() error {
91 return prisma.Prisma.QueryRaw("SELECT 1").Exec(context.Background(), nil)
92}
93
94func CheckFirebaseHealth() error {
95 if !config.HasValidFirebaseServiceAccount() {
96 return nil
97 }
98
99 fcm, err := firebaseClient.Messaging(firebaseCtx)
100 if err != nil {
101 return fmt.Errorf("while initializing messaging client: %w", err)
102 }
103
104 _, err = fcm.SendDryRun(firebaseCtx, &messaging.Message{
105 Notification: &messaging.Notification{
106 Title: "Health check attempt",
107 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.",
108 },
109 Token: "invalid",
110 })
111 if err != nil && err.Error() == "The registration token is not a valid FCM registration token" {
112 return nil
113 }
114 return err
115}