83 lines
1.8 KiB
Go
83 lines
1.8 KiB
Go
package health
|
|
|
|
import (
|
|
"context"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
type (
|
|
Checker func(ctx context.Context) HealthCheck
|
|
|
|
HealthCheck struct {
|
|
Name string `json:"name"`
|
|
Status Status `json:"status"`
|
|
Message string `json:"message,omitempty"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Duration time.Duration `json:"duration"`
|
|
Details map[string]interface{} `json:"details,omitempty"`
|
|
}
|
|
|
|
HealthResponse struct {
|
|
Status Status `json:"status"`
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Version string `json:"version"`
|
|
Checks map[string]HealthCheck `json:"checks"`
|
|
Details map[string]interface{} `json:"details,omitempty"`
|
|
}
|
|
)
|
|
|
|
func Health(ctx context.Context, version string, checkers ...Checker) HealthResponse {
|
|
start := time.Now()
|
|
|
|
results := make(map[string]HealthCheck, len(checkers))
|
|
wg := sync.WaitGroup{}
|
|
mu := sync.Mutex{}
|
|
|
|
wg.Add(len(checkers))
|
|
for _, checker := range checkers {
|
|
go func(c Checker) {
|
|
defer wg.Done()
|
|
check := c(ctx)
|
|
mu.Lock()
|
|
results[check.Name] = check
|
|
mu.Unlock()
|
|
}(checker)
|
|
}
|
|
wg.Wait()
|
|
|
|
// Determine overall status
|
|
overallStatus := determineOverallStatus(results)
|
|
|
|
return HealthResponse{
|
|
Status: overallStatus,
|
|
Timestamp: time.Now(),
|
|
Version: version,
|
|
Checks: results,
|
|
Details: map[string]interface{}{
|
|
"uptime": time.Since(start).String(),
|
|
},
|
|
}
|
|
}
|
|
|
|
func determineOverallStatus(checks map[string]HealthCheck) Status {
|
|
var unhealthyCount, degradedCount int
|
|
for _, c := range checks {
|
|
switch c.Status {
|
|
case StatusUnhealthy:
|
|
unhealthyCount++
|
|
case StatusDegraded:
|
|
degradedCount++
|
|
}
|
|
}
|
|
|
|
switch {
|
|
case unhealthyCount > 0:
|
|
return StatusUnhealthy
|
|
case degradedCount > 0:
|
|
return StatusDegraded
|
|
default:
|
|
return StatusHealthy
|
|
}
|
|
}
|