// Package healthcheck provides application health status. package healthcheck import ( "context" "log/slog" "time" "go.uber.org/fx" "git.eeqj.de/sneak/upaas/internal/config" "git.eeqj.de/sneak/upaas/internal/database" "git.eeqj.de/sneak/upaas/internal/globals" "git.eeqj.de/sneak/upaas/internal/logger" ) // Params contains dependencies for Healthcheck. type Params struct { fx.In Globals *globals.Globals Config *config.Config Logger *logger.Logger Database *database.Database } // Healthcheck provides health status information. type Healthcheck struct { StartupTime time.Time log *slog.Logger params *Params } // Response is the health check response structure. type Response struct { Status string `json:"status"` Now string `json:"now"` UptimeSeconds int64 `json:"uptimeSeconds"` UptimeHuman string `json:"uptimeHuman"` Version string `json:"version"` Appname string `json:"appname"` Maintenance bool `json:"maintenanceMode"` } // New creates a new Healthcheck instance. func New(lifecycle fx.Lifecycle, params Params) (*Healthcheck, error) { healthcheck := &Healthcheck{ log: params.Logger.Get(), params: ¶ms, } // For testing, if lifecycle is nil, initialize immediately if lifecycle == nil { healthcheck.StartupTime = time.Now() return healthcheck, nil } lifecycle.Append(fx.Hook{ OnStart: func(_ context.Context) error { healthcheck.StartupTime = time.Now() return nil }, }) return healthcheck, nil } // Check returns the current health status. func (h *Healthcheck) Check() *Response { return &Response{ Status: "ok", Now: time.Now().UTC().Format(time.RFC3339Nano), UptimeSeconds: int64(h.uptime().Seconds()), UptimeHuman: h.uptime().String(), Appname: h.params.Globals.Appname, Version: h.params.Globals.Version, Maintenance: h.params.Config.MaintenanceMode, } } func (h *Healthcheck) uptime() time.Duration { return time.Since(h.StartupTime) }