package healthhttp import ( "context" "encoding/json" "net/http" "time" "gitea.dwysokinski.me/twhelp/core/internal/health" ) type handler struct { check func(ctx context.Context) health.Result } var _ http.Handler = (*handler)(nil) func LiveHandler(h *health.Health) http.Handler { return &handler{ check: h.CheckLive, } } func ReadyHandler(h *health.Health) http.Handler { return &handler{ check: h.CheckReady, } } type singleCheckResult struct { Status string `json:"status"` FailureReason string `json:"err,omitempty"` Time time.Time `json:"time"` } type response struct { Status string `json:"status"` Checks map[string][]singleCheckResult `json:"checks"` } func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ctx := r.Context() result := h.check(ctx) select { case <-ctx.Done(): return default: } respChecks := make(map[string][]singleCheckResult, len(result.Checks)) for name, checks := range result.Checks { respChecks[name] = make([]singleCheckResult, 0, len(checks)) for _, ch := range checks { failureReason := "" if ch.Err != nil { failureReason = ch.Err.Error() } respChecks[name] = append(respChecks[name], singleCheckResult{ Status: ch.Status.String(), FailureReason: failureReason, Time: ch.Time, }) } } w.Header().Set("Content-Type", "application/json") w.WriteHeader(healthStatusToHTTPStatus(result.Status)) _ = json.NewEncoder(w).Encode(response{ Status: result.Status.String(), Checks: respChecks, }) } func healthStatusToHTTPStatus(status health.Status) int { switch status { case health.StatusPass: return http.StatusOK case health.StatusFail: return http.StatusServiceUnavailable default: return http.StatusInternalServerError } }