| | | 1 | | using Chronicis.Shared.DTOs; |
| | | 2 | | |
| | | 3 | | namespace Chronicis.Api.Services; |
| | | 4 | | |
| | | 5 | | public interface ISystemHealthService |
| | | 6 | | { |
| | | 7 | | Task<SystemHealthStatusDto> GetSystemHealthAsync(); |
| | | 8 | | } |
| | | 9 | | |
| | | 10 | | public class SystemHealthService : ISystemHealthService |
| | | 11 | | { |
| | | 12 | | private readonly DatabaseHealthCheckService _databaseHealth; |
| | | 13 | | private readonly AzureOpenAIHealthCheckService _azureOpenAIHealth; |
| | | 14 | | private readonly BlobStorageHealthCheckService _blobStorageHealth; |
| | | 15 | | private readonly Auth0HealthCheckService _auth0Health; |
| | | 16 | | private readonly Open5eHealthCheckService _open5eHealth; |
| | | 17 | | private readonly ILogger<SystemHealthService> _logger; |
| | | 18 | | |
| | 0 | 19 | | public SystemHealthService( |
| | 0 | 20 | | DatabaseHealthCheckService databaseHealth, |
| | 0 | 21 | | AzureOpenAIHealthCheckService azureOpenAIHealth, |
| | 0 | 22 | | BlobStorageHealthCheckService blobStorageHealth, |
| | 0 | 23 | | Auth0HealthCheckService auth0Health, |
| | 0 | 24 | | Open5eHealthCheckService open5eHealth, |
| | 0 | 25 | | ILogger<SystemHealthService> logger) |
| | | 26 | | { |
| | 0 | 27 | | _databaseHealth = databaseHealth; |
| | 0 | 28 | | _azureOpenAIHealth = azureOpenAIHealth; |
| | 0 | 29 | | _blobStorageHealth = blobStorageHealth; |
| | 0 | 30 | | _auth0Health = auth0Health; |
| | 0 | 31 | | _open5eHealth = open5eHealth; |
| | 0 | 32 | | _logger = logger; |
| | 0 | 33 | | } |
| | | 34 | | |
| | | 35 | | public async Task<SystemHealthStatusDto> GetSystemHealthAsync() |
| | | 36 | | { |
| | 0 | 37 | | var timestamp = DateTime.UtcNow; |
| | 0 | 38 | | _logger.LogInformation("Starting system health check"); |
| | | 39 | | |
| | | 40 | | // Run all health checks in parallel |
| | 0 | 41 | | var healthCheckTasks = new[] |
| | 0 | 42 | | { |
| | 0 | 43 | | _databaseHealth.CheckHealthAsync("Database", ServiceKeys.Database), |
| | 0 | 44 | | _azureOpenAIHealth.CheckHealthAsync("Azure OpenAI", ServiceKeys.AzureOpenAI), |
| | 0 | 45 | | _blobStorageHealth.CheckHealthAsync("Document Storage", ServiceKeys.BlobStorage), |
| | 0 | 46 | | _auth0Health.CheckHealthAsync("Auth0", ServiceKeys.Auth0), |
| | 0 | 47 | | _open5eHealth.CheckHealthAsync("Open5e API", ServiceKeys.Open5e) |
| | 0 | 48 | | }; |
| | | 49 | | |
| | | 50 | | // Add API self-check |
| | 0 | 51 | | var apiHealthTask = Task.FromResult(new ServiceHealthDto |
| | 0 | 52 | | { |
| | 0 | 53 | | Name = "API", |
| | 0 | 54 | | ServiceKey = ServiceKeys.Api, |
| | 0 | 55 | | Status = HealthStatus.Healthy, |
| | 0 | 56 | | Message = "API is responding", |
| | 0 | 57 | | ResponseTimeMs = 0, |
| | 0 | 58 | | CheckedAt = timestamp |
| | 0 | 59 | | }); |
| | | 60 | | |
| | 0 | 61 | | var allTasks = healthCheckTasks.Concat(new[] { apiHealthTask }).ToArray(); |
| | 0 | 62 | | var results = await Task.WhenAll(allTasks); |
| | | 63 | | |
| | | 64 | | // Determine overall status |
| | 0 | 65 | | var overallStatus = DetermineOverallStatus(results); |
| | | 66 | | |
| | 0 | 67 | | _logger.LogInformation("System health check completed. Overall status: {Status}", overallStatus); |
| | | 68 | | |
| | 0 | 69 | | return new SystemHealthStatusDto |
| | 0 | 70 | | { |
| | 0 | 71 | | Timestamp = timestamp, |
| | 0 | 72 | | OverallStatus = overallStatus, |
| | 0 | 73 | | Services = results.ToList() |
| | 0 | 74 | | }; |
| | 0 | 75 | | } |
| | | 76 | | |
| | | 77 | | private static string DetermineOverallStatus(ServiceHealthDto[] services) |
| | | 78 | | { |
| | 0 | 79 | | var hasUnhealthy = services.Any(s => s.Status == HealthStatus.Unhealthy); |
| | 0 | 80 | | var hasDegraded = services.Any(s => s.Status == HealthStatus.Degraded); |
| | | 81 | | |
| | 0 | 82 | | if (hasUnhealthy) |
| | 0 | 83 | | return HealthStatus.Unhealthy; |
| | | 84 | | |
| | 0 | 85 | | if (hasDegraded) |
| | 0 | 86 | | return HealthStatus.Degraded; |
| | | 87 | | |
| | 0 | 88 | | return HealthStatus.Healthy; |
| | | 89 | | } |
| | | 90 | | } |