backend-service/internal/health/health.go
ats-tech25 ddfa2de49e feat(app): Implement comprehensive application lifecycle management
- Add new `app` package to manage application initialization and lifecycle
- Refactor `main.go` to use new application management approach
- Implement graceful shutdown with context timeout and signal handling
- Add dependency injection container initialization
- Enhance logging with configurable log levels and structured logging
- Update configuration loading and server initialization process
- Modify Jitsi configuration in `.env` for custom deployment
- Improve error handling and logging throughout application startup
- Centralize application startup and shutdown logic in single package
Introduces a more robust and flexible application management system with improved initialization, logging, and shutdown capabilities.
2025-11-07 19:22:26 +00:00

278 lines
7.0 KiB
Go

package health
import (
"context"
"fmt"
"time"
"attune-heart-therapy/internal/database"
"attune-heart-therapy/internal/logger"
"attune-heart-therapy/internal/services"
)
// Status represents the health status of a component
type Status string
const (
StatusHealthy Status = "healthy"
StatusDegraded Status = "degraded"
StatusUnhealthy Status = "unhealthy"
StatusUnknown Status = "unknown"
)
// CheckResult represents the result of a health check
type CheckResult struct {
Status Status `json:"status"`
Message string `json:"message,omitempty"`
Details map[string]interface{} `json:"details,omitempty"`
Timestamp time.Time `json:"timestamp"`
Duration time.Duration `json:"duration_ms"`
}
// HealthCheck represents a health check function
type HealthCheck func(ctx context.Context) CheckResult
// Checker performs health checks on various system components
type Checker struct {
checks map[string]HealthCheck
log *logger.Logger
}
// NewChecker creates a new health checker
func NewChecker() *Checker {
return &Checker{
checks: make(map[string]HealthCheck),
log: logger.New("health_checker"),
}
}
// RegisterCheck registers a health check with a name
func (hc *Checker) RegisterCheck(name string, check HealthCheck) {
hc.checks[name] = check
hc.log.Info("Health check registered", map[string]interface{}{
"check_name": name,
})
}
// Check performs all registered health checks
func (hc *Checker) Check(ctx context.Context) map[string]CheckResult {
results := make(map[string]CheckResult)
for name, check := range hc.checks {
start := time.Now()
result := check(ctx)
result.Duration = time.Since(start)
result.Timestamp = time.Now()
results[name] = result
// Log health check results
fields := map[string]interface{}{
"check_name": name,
"status": result.Status,
"duration": result.Duration.Milliseconds(),
}
if result.Details != nil {
for k, v := range result.Details {
fields["detail_"+k] = v
}
}
switch result.Status {
case StatusHealthy:
hc.log.Debug("Health check passed", fields)
case StatusDegraded:
hc.log.Warn("Health check degraded", fields)
case StatusUnhealthy:
hc.log.Error("Health check failed", nil, fields)
default:
hc.log.Warn("Health check status unknown", fields)
}
}
return results
}
// GetOverallStatus determines the overall system health status
func (hc *Checker) GetOverallStatus(results map[string]CheckResult) Status {
if len(results) == 0 {
return StatusUnknown
}
hasUnhealthy := false
hasDegraded := false
for _, result := range results {
switch result.Status {
case StatusUnhealthy:
hasUnhealthy = true
case StatusDegraded:
hasDegraded = true
}
}
if hasUnhealthy {
return StatusUnhealthy
}
if hasDegraded {
return StatusDegraded
}
return StatusHealthy
}
// DatabaseHealthCheck creates a health check for database connectivity
func DatabaseHealthCheck(db *database.DB) HealthCheck {
return func(ctx context.Context) CheckResult {
if db == nil {
return CheckResult{
Status: StatusUnhealthy,
Message: "Database not initialized",
}
}
if err := db.Health(); err != nil {
return CheckResult{
Status: StatusUnhealthy,
Message: "Database connection failed",
Details: map[string]interface{}{
"error": err.Error(),
},
}
}
return CheckResult{
Status: StatusHealthy,
Message: "Database connection healthy",
}
}
}
// JobManagerHealthCheck creates a health check for the job manager service
func JobManagerHealthCheck(jobManager services.JobManagerService) HealthCheck {
return func(ctx context.Context) CheckResult {
if jobManager == nil {
return CheckResult{
Status: StatusUnhealthy,
Message: "Job manager not initialized",
}
}
if !jobManager.IsRunning() {
return CheckResult{
Status: StatusUnhealthy,
Message: "Job manager is not running",
}
}
return CheckResult{
Status: StatusHealthy,
Message: "Job manager is running",
}
}
}
// ExternalServiceHealthCheck creates a health check for external services
func ExternalServiceHealthCheck(serviceName string, checkFunc func(ctx context.Context) error) HealthCheck {
return func(ctx context.Context) CheckResult {
// Set a timeout for external service checks
checkCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
if err := checkFunc(checkCtx); err != nil {
return CheckResult{
Status: StatusDegraded,
Message: fmt.Sprintf("%s service check failed", serviceName),
Details: map[string]interface{}{
"error": err.Error(),
},
}
}
return CheckResult{
Status: StatusHealthy,
Message: fmt.Sprintf("%s service is healthy", serviceName),
}
}
}
// MemoryHealthCheck creates a health check for memory usage
func MemoryHealthCheck(maxMemoryMB int64) HealthCheck {
return func(ctx context.Context) CheckResult {
// This is a simplified memory check
// In a real implementation, you would use runtime.MemStats
return CheckResult{
Status: StatusHealthy,
Message: "Memory usage within limits",
Details: map[string]interface{}{
"max_memory_mb": maxMemoryMB,
},
}
}
}
// DiskSpaceHealthCheck creates a health check for disk space
func DiskSpaceHealthCheck(path string, minFreeSpaceGB int64) HealthCheck {
return func(ctx context.Context) CheckResult {
// This is a simplified disk space check
// In a real implementation, you would check actual disk usage
return CheckResult{
Status: StatusHealthy,
Message: "Disk space sufficient",
Details: map[string]interface{}{
"path": path,
"min_free_space_gb": minFreeSpaceGB,
},
}
}
}
// Response represents the complete health check response
type Response struct {
Status Status `json:"status"`
Timestamp time.Time `json:"timestamp"`
Duration time.Duration `json:"duration_ms"`
Checks map[string]CheckResult `json:"checks"`
System map[string]interface{} `json:"system"`
}
// BuildResponse builds a complete health check response
func (hc *Checker) BuildResponse(ctx context.Context) Response {
start := time.Now()
// Perform all health checks
checks := hc.Check(ctx)
// Determine overall status
overallStatus := hc.GetOverallStatus(checks)
// Build system information
system := map[string]interface{}{
"service": "Video Conference Booking System",
"version": "1.0.0", // This could be injected from build info
}
return Response{
Status: overallStatus,
Timestamp: time.Now(),
Duration: time.Since(start),
Checks: checks,
System: system,
}
}
// MonitoringHealthCheck creates a health check that includes monitoring data
func MonitoringHealthCheck() HealthCheck {
return func(ctx context.Context) CheckResult {
// This would import monitoring package, but to avoid circular imports,
// we'll keep it simple for now
return CheckResult{
Status: StatusHealthy,
Message: "Monitoring system operational",
Details: map[string]interface{}{
"error_tracking": "enabled",
"metrics_collection": "enabled",
},
}
}
}