core/internal/health/healthhttp/handler.go

88 lines
1.8 KiB
Go

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
}
}