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