BCards/src/BCards.Web/HealthChecks/ExternalServicesHealthCheck.cs
Ricardo Carneiro d700bd35a9
All checks were successful
BCards Deployment Pipeline / Run Tests (push) Successful in 4s
BCards Deployment Pipeline / PR Validation (push) Has been skipped
BCards Deployment Pipeline / Build and Push Image (push) Successful in 7m58s
BCards Deployment Pipeline / Deploy to Production (ARM - OCI) (push) Successful in 1m39s
BCards Deployment Pipeline / Deploy to Staging (x86 - Local) (push) Has been skipped
BCards Deployment Pipeline / Cleanup Old Resources (push) Has been skipped
BCards Deployment Pipeline / Deployment Summary (push) Successful in 1s
fix: ajustes de notificações e restrição de tamanho da imagem
2025-09-05 17:49:26 -03:00

134 lines
5.2 KiB
C#

using Microsoft.Extensions.Diagnostics.HealthChecks;
using System.Diagnostics;
namespace BCards.Web.HealthChecks;
public class ExternalServicesHealthCheck : IHealthCheck
{
private readonly HttpClient _httpClient;
private readonly ILogger<ExternalServicesHealthCheck> _logger;
public ExternalServicesHealthCheck(HttpClient httpClient, ILogger<ExternalServicesHealthCheck> logger)
{
_httpClient = httpClient;
_logger = logger;
}
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
var stopwatch = Stopwatch.StartNew();
var results = new Dictionary<string, object>();
var allHealthy = true;
var hasUnhealthy = false;
try
{
// Lista de serviços externos para verificar
var services = new Dictionary<string, string>
{
{ "google_oauth", "https://accounts.google.com" },
{ "microsoft_oauth", "https://login.microsoftonline.com" }
};
foreach (var service in services)
{
var serviceStopwatch = Stopwatch.StartNew();
try
{
using var response = await _httpClient.GetAsync(service.Value, cancellationToken);
serviceStopwatch.Stop();
var serviceResult = new Dictionary<string, object>
{
{ "status", response.IsSuccessStatusCode ? "healthy" : "unhealthy" },
{ "duration", $"{serviceStopwatch.ElapsedMilliseconds}ms" },
{ "status_code", (int)response.StatusCode },
{ "url", service.Value }
};
results[service.Key] = serviceResult;
if (!response.IsSuccessStatusCode)
{
allHealthy = false;
if (response.StatusCode == System.Net.HttpStatusCode.ServiceUnavailable ||
response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
{
hasUnhealthy = true;
}
}
_logger.LogInformation("External service {Service} health check: {Status} in {Duration}ms",
service.Key, response.StatusCode, serviceStopwatch.ElapsedMilliseconds);
}
catch (Exception ex)
{
serviceStopwatch.Stop();
allHealthy = false;
hasUnhealthy = true;
results[service.Key] = new Dictionary<string, object>
{
{ "status", "unhealthy" },
{ "duration", $"{serviceStopwatch.ElapsedMilliseconds}ms" },
{ "error", ex.Message },
{ "url", service.Value }
};
// Usar Warning para OAuth providers (alerta amarelo)
if (service.Key.Contains("oauth"))
{
_logger.LogWarning("🟡 OAuth service {Service} offline - usuários não conseguem fazer login: {Error}",
service.Key, ex.Message);
}
else
{
_logger.LogError(ex, "🔴 Critical service {Service} failed", service.Key);
}
}
}
stopwatch.Stop();
var totalDuration = stopwatch.ElapsedMilliseconds;
var data = new Dictionary<string, object>
{
{ "status", hasUnhealthy ? "unhealthy" : (allHealthy ? "healthy" : "degraded") },
{ "duration", $"{totalDuration}ms" },
{ "services", results },
{ "total_services", services.Count },
{ "healthy_services", results.Values.Count(r => ((Dictionary<string, object>)r)["status"].ToString() == "healthy") }
};
if (hasUnhealthy)
{
return HealthCheckResult.Unhealthy("One or more external services are unhealthy", data: data);
}
if (!allHealthy)
{
return HealthCheckResult.Degraded("Some external services have issues", data: data);
}
return HealthCheckResult.Healthy($"All external services are responsive ({totalDuration}ms)", data: data);
}
catch (Exception ex)
{
stopwatch.Stop();
var duration = stopwatch.ElapsedMilliseconds;
_logger.LogError(ex, "External services health check failed after {Duration}ms", duration);
var data = new Dictionary<string, object>
{
{ "status", "unhealthy" },
{ "duration", $"{duration}ms" },
{ "error", ex.Message }
};
return HealthCheckResult.Unhealthy($"External services check failed: {ex.Message}", ex, data);
}
}
}