Skip to content
This repository was archived by the owner on Dec 28, 2024. It is now read-only.

Commit 1a7d81c

Browse files
committed
Add healthchecks to service images
1 parent b126da2 commit 1a7d81c

File tree

3 files changed

+54
-17
lines changed

3 files changed

+54
-17
lines changed

Dockerfile

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
FROM golang:1.23-alpine
1+
FROM golang:1.23-alpine AS golang-with-curl
2+
RUN apk --no-cache add curl
3+
4+
FROM golang-with-curl
25
WORKDIR /app
36
COPY go.mod .
47
COPY common common
@@ -7,4 +10,11 @@ ARG DAY
710
COPY solutions/day${DAY} solutions/day${DAY}
811
RUN go build -o app solutions/day${DAY}/main.go
912
EXPOSE 3000
13+
14+
HEALTHCHECK \
15+
--start-interval=10s \
16+
--interval=10s \
17+
--timeout=3s \
18+
CMD curl -f http://127.0.0.1:3000/health
19+
1020
CMD ["./app"]

client/run.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func runSolution(
7272
defer resp.Body.Close()
7373
body, bodyReadErr := io.ReadAll(resp.Body)
7474

75-
if resp.StatusCode != 200 && bodyReadErr == nil {
75+
if resp.StatusCode != 200 && bodyReadErr != nil {
7676
return "", fmt.Errorf("unexpected status code %d", resp.StatusCode)
7777
} else if resp.StatusCode != 200 {
7878
return "", fmt.Errorf("unexpected status code %d: '%s'", resp.StatusCode, body)

common/setup.go

Lines changed: 42 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package common
22

33
import (
4-
"errors"
54
"fmt"
65
"io"
76
"log"
@@ -15,25 +14,30 @@ func Setup(
1514
part1 Solution,
1615
part2 Solution,
1716
) {
18-
http.HandleFunc("/1", createHandler(day, 1, part1))
19-
http.HandleFunc("/2", createHandler(day, 2, part2))
17+
http.HandleFunc("/1", createSolutionHandler(day, 1, part1))
18+
http.HandleFunc("/2", createSolutionHandler(day, 2, part2))
19+
http.HandleFunc("/health", healthCheckHandler)
20+
http.HandleFunc("/health/live", healthCheckHandler)
21+
http.HandleFunc("/health/ready", healthCheckHandler)
22+
2023
fmt.Printf("Starting Day #%d service on port 3000\n", day)
2124
if err := http.ListenAndServe(":3000", nil); err != nil {
2225
log.Fatal(err)
26+
2327
}
2428
}
2529

26-
func createHandler(
30+
func createSolutionHandler(
2731
day int,
2832
part int,
2933
solution func(string) string,
3034
) func(http.ResponseWriter, *http.Request) {
3135
if solution == nil {
32-
solution = defaultHandler(day, part)
36+
solution = defaultSolutionHandler(day, part)
3337
}
3438

3539
return func(w http.ResponseWriter, r *http.Request) {
36-
if err := methodMustBePost(w, r); err != nil {
40+
if err := whitelistMethods([]string{"POST"}, w, r); err != nil {
3741
fmt.Print(err.Error())
3842
return
3943
}
@@ -45,15 +49,29 @@ func createHandler(
4549
}
4650

4751
result := solution(input)
48-
_, err = w.Write([]byte(result))
49-
if err != nil {
52+
if _, err = w.Write([]byte(result)); err != nil {
5053
http.Error(w, "Error", http.StatusInternalServerError)
5154
return
5255
}
5356
}
5457
}
5558

56-
func defaultHandler(
59+
func healthCheckHandler(
60+
w http.ResponseWriter,
61+
r *http.Request,
62+
) {
63+
if err := whitelistMethods([]string{"GET", "POST"}, w, r); err != nil {
64+
fmt.Print(err.Error())
65+
return
66+
}
67+
68+
if _, err := w.Write([]byte("{ \"status\": \"UP\" }")); err != nil {
69+
http.Error(w, "Error", http.StatusInternalServerError)
70+
return
71+
}
72+
}
73+
74+
func defaultSolutionHandler(
5775
day int,
5876
part int,
5977
) Solution {
@@ -62,14 +80,23 @@ func defaultHandler(
6280
}
6381
}
6482

65-
func methodMustBePost(w http.ResponseWriter, r *http.Request) error {
66-
if r.Method != http.MethodPost {
67-
http.Error(w, "Only POST method is allowed", http.StatusMethodNotAllowed)
68-
msg := fmt.Sprintf("Expected method to be POST, but was %s\n", r.Method)
69-
return errors.New(msg)
83+
func whitelistMethods(
84+
methods []string,
85+
w http.ResponseWriter,
86+
r *http.Request,
87+
) error {
88+
for _, method := range methods {
89+
if r.Method == method {
90+
return nil
91+
}
7092
}
7193

72-
return nil
94+
http.Error(
95+
w,
96+
fmt.Sprintf("%s is not in allowed methods: %q", r.Method, methods),
97+
http.StatusMethodNotAllowed,
98+
)
99+
return fmt.Errorf("expected method to be one of %q, but was %s", methods, r.Method)
73100
}
74101

75102
func readInput(r *http.Request) (string, error) {

0 commit comments

Comments
 (0)