Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NBHF4R9EAejDJUMdwr6C68
62 lines
1.5 KiB
Go
62 lines
1.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
|
|
"git.ravensburg.dev/cabele/opnsense-portal/internal/check"
|
|
"git.ravensburg.dev/cabele/opnsense-portal/internal/web"
|
|
)
|
|
|
|
// healthCacheTTL verhindert, dass häufige Monitoring-Abfragen Firewall und
|
|
// Verzeichnis belasten.
|
|
const healthCacheTTL = 30 * time.Second
|
|
|
|
// directoryPinger ist der für /healthz benötigte Ausschnitt des AD-Clients.
|
|
type directoryPinger interface {
|
|
ResolveGroupDN(ctx context.Context) (string, error)
|
|
}
|
|
|
|
// healthChecker beantwortet /healthz mit kurz gecachten Ergebnissen.
|
|
type healthChecker struct {
|
|
fw check.Pinger
|
|
dir directoryPinger
|
|
clock func() time.Time
|
|
|
|
mu sync.Mutex
|
|
cached web.HealthReport
|
|
cachedAt time.Time
|
|
}
|
|
|
|
func newHealthChecker(fw check.Pinger, dir directoryPinger) *healthChecker {
|
|
return &healthChecker{fw: fw, dir: dir, clock: time.Now}
|
|
}
|
|
|
|
func (h *healthChecker) Check(ctx context.Context) web.HealthReport {
|
|
now := h.clock()
|
|
h.mu.Lock()
|
|
if !h.cachedAt.IsZero() && now.Sub(h.cachedAt) < healthCacheTTL {
|
|
rep := h.cached
|
|
h.mu.Unlock()
|
|
return rep
|
|
}
|
|
h.mu.Unlock()
|
|
|
|
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
|
|
defer cancel()
|
|
|
|
var rep web.HealthReport
|
|
_, fwErr := h.fw.Ping(ctx)
|
|
rep.OPNsense = fwErr == nil
|
|
_, dirErr := h.dir.ResolveGroupDN(ctx)
|
|
rep.Directory = dirErr == nil
|
|
rep.OK = rep.OPNsense && rep.Directory
|
|
|
|
h.mu.Lock()
|
|
h.cached, h.cachedAt = rep, now
|
|
h.mu.Unlock()
|
|
return rep
|
|
}
|
|
|
|
var _ web.HealthChecker = (*healthChecker)(nil)
|