- 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.
278 lines
7.0 KiB
Go
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",
|
|
},
|
|
}
|
|
}
|
|
}
|