< Summary

Information
Class: Infrastructure.Service.HealthCheckResilienceService
Assembly: Infrastructure
File(s): /home/runner/work/Northwind-Api/Northwind-Api/src/Infrastructure/Service/HealthCheckResilienceService.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 55
Coverable lines: 55
Total lines: 80
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 26
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%210%
WaitForHealthyStatusAsync()0%702260%
RunManuallyAsync()100%210%
StartAsync()100%210%
StopAsync(...)100%210%

File(s)

/home/runner/work/Northwind-Api/Northwind-Api/src/Infrastructure/Service/HealthCheckResilienceService.cs

#LineLine coverage
 1using Microsoft.Extensions.Diagnostics.HealthChecks;
 2using Microsoft.Extensions.Hosting;
 3using Microsoft.Extensions.Logging;
 4
 5namespace Infrastructure.Service;
 6public class HealthCheckResilienceService : IHostedService {
 7  private readonly ILogger<HealthCheckResilienceService>? _logger;
 8  private readonly HealthCheckService _service;
 9
 010  public HealthCheckResilienceService(ILogger<HealthCheckResilienceService>? logger, HealthCheckService service) {
 011    _logger = logger;
 012    _service = service;
 013  }
 14
 15  private const int MAX_RETRIES = 10;
 16  private const int RETRY_DELAY = 5;
 17
 018  public async Task WaitForHealthyStatusAsync(CancellationToken ct = default) {
 019    var isHealthy = false;
 20
 021    for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) {
 022      try {
 023        var healthReport = await _service.CheckHealthAsync(ct);
 24
 025        if (healthReport.Status == HealthStatus.Healthy) {
 026          _logger?.LogInformation("Health check passed on attempt {Attempt}.", attempt);
 027          isHealthy = true;
 028          break;
 29        }
 30
 031        _logger?.LogWarning(
 032          "Health check failed on attempt {Attempt}/{MaxRetries}. Retrying in {RetryDelaySeconds} seconds...",
 033          attempt,
 034          MAX_RETRIES,
 035          RETRY_DELAY
 036        );
 37
 038        foreach (var entry in healthReport.Entries) {
 039          _logger?.LogWarning(
 040            "Health check entry {Key}: {Status} - {Description}",
 041            entry.Key,
 042            entry.Value.Status,
 043            entry.Value.Description
 044          );
 045        }
 046      }
 047      catch (Exception ex) {
 048        _logger?.LogError(
 049          ex,
 050          "An exception occurred during health check attempt {Attempt}/{MaxRetries}.",
 051          attempt,
 052          MAX_RETRIES
 053        );
 054      }
 55
 056      for (int remainingSeconds = RETRY_DELAY; remainingSeconds > 0; remainingSeconds--) {
 057        _logger?.LogInformation("Retrying in {RemainingSeconds} second(s)...", remainingSeconds);
 058        await Task.Delay(TimeSpan.FromSeconds(1), ct);
 059      }
 060    }
 61
 062    if (!isHealthy) {
 063      _logger?.LogError("-------------------------------------------------------------------------------");
 064      _logger?.LogError("Health check failed after {MaxRetries:D2} attempts. Application starting as not operational!", 
 065      _logger?.LogError("-------------------------------------------------------------------------------");
 066    };
 067  }
 68
 069  public async Task RunManuallyAsync(CancellationToken ct = default) {
 070    await StartAsync(ct);
 071  }
 72
 073  public async Task StartAsync(CancellationToken ct) {
 074    await WaitForHealthyStatusAsync(ct);
 075  }
 76
 077  public Task StopAsync(CancellationToken ct) {
 078    throw new NotImplementedException();
 79  }
 80}