Go · 1398 bytes Raw Blame History
1 // SPDX-License-Identifier: AGPL-3.0-or-later
2
3 package handlers
4
5 import (
6 "context"
7 "log/slog"
8 "net/http"
9 "time"
10 )
11
12 // healthz returns 200 if the process is alive. No dependency checks.
13 func healthz(w http.ResponseWriter, _ *http.Request) {
14 w.Header().Set("Content-Type", "text/plain; charset=utf-8")
15 w.Header().Set("Cache-Control", "no-store")
16 _, _ = w.Write([]byte("ok\n"))
17 }
18
19 // readinessHandler returns a /readyz handler that calls check (when non-nil)
20 // with a 2-second budget. A nil error returns 200 ready; a non-nil error
21 // returns 503 with the error reason in the body. When check is nil the
22 // handler always reports ready (the S00 default for a DB-less boot).
23 func readinessHandler(check func(context.Context) error, logger *slog.Logger) http.Handler {
24 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
25 w.Header().Set("Content-Type", "text/plain; charset=utf-8")
26 w.Header().Set("Cache-Control", "no-store")
27 if check == nil {
28 _, _ = w.Write([]byte("ready\n"))
29 return
30 }
31 ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second)
32 defer cancel()
33 if err := check(ctx); err != nil {
34 if logger != nil {
35 logger.Warn("readyz: dependency unhealthy", "error", err)
36 }
37 w.WriteHeader(http.StatusServiceUnavailable)
38 _, _ = w.Write([]byte("not ready: " + err.Error() + "\n"))
39 return
40 }
41 _, _ = w.Write([]byte("ready\n"))
42 })
43 }
44