< Summary

Information
Class: Infrastructure.Service.HealthCheckResilienceService
Assembly: Infrastructure
File(s): /home/runner/work/CleanArchitectureTemplate/CleanArchitectureTemplate/src/Infrastructure/Service/HealthCheckResilienceService.cs
Line coverage
0%
Covered lines: 0
Uncovered lines: 56
Coverable lines: 56
Total lines: 82
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/CleanArchitectureTemplate/CleanArchitectureTemplate/src/Infrastructure/Service/HealthCheckResilienceService.cs

#LineLine coverage
 1using Microsoft.Extensions.Diagnostics.HealthChecks;
 2using Microsoft.Extensions.Hosting;
 3using Microsoft.Extensions.Logging;
 4
 5namespace Infrastructure.Service;
 6
 7public class HealthCheckResilienceService : IHostedService {
 8  private readonly ILogger<HealthCheckResilienceService>? _logger;
 9  private readonly HealthCheckService _service;
 10
 011  public HealthCheckResilienceService(ILogger<HealthCheckResilienceService>? logger, HealthCheckService service) {
 012    _logger = logger;
 013    _service = service;
 014  }
 15
 16  private const int MAX_RETRIES = 10;
 17  private const int RETRY_DELAY = 5;
 18
 019  public async Task WaitForHealthyStatusAsync(CancellationToken cancellationToken = default) {
 020    var isHealthy = false;
 21
 022    for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) {
 023      try {
 024        var healthReport = await _service.CheckHealthAsync(cancellationToken);
 25
 026        if (healthReport.Status == HealthStatus.Healthy) {
 027          _logger?.LogInformation("Health check passed on attempt {Attempt}.", attempt);
 028          isHealthy = true;
 029          break;
 30        }
 31
 032        _logger?.LogWarning(
 033          "Health check failed on attempt {Attempt}/{MaxRetries}. Retrying in {RetryDelaySeconds} seconds...",
 034          attempt,
 035          MAX_RETRIES,
 036          RETRY_DELAY
 037        );
 38
 039        foreach (var entry in healthReport.Entries) {
 040          _logger?.LogWarning(
 041            "Health check entry {Key}: {Status} - {Description}",
 042            entry.Key,
 043            entry.Value.Status,
 044            entry.Value.Description
 045          );
 046        }
 047      }
 048      catch (Exception ex) {
 049        _logger?.LogError(
 050          ex,
 051          "An exception occurred during health check attempt {Attempt}/{MaxRetries}.",
 052          attempt,
 053          MAX_RETRIES
 054        );
 055      }
 56
 057      for (int remainingSeconds = RETRY_DELAY; remainingSeconds > 0; remainingSeconds--) {
 058        _logger?.LogInformation("Retrying in {RemainingSeconds} second(s)...", remainingSeconds);
 059        await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
 060      }
 061    }
 62
 063    if (!isHealthy) {
 064      _logger?.LogError("-------------------------------------------------------------------------------");
 065      _logger?.LogError("Health check failed after {MaxRetries:D2} attempts. Application starting as not operational!", 
 066      _logger?.LogError("-------------------------------------------------------------------------------");
 067    }
 068    ;
 069  }
 70
 071  public async Task RunManuallyAsync(CancellationToken cancellationToken = default) {
 072    await StartAsync(cancellationToken);
 073  }
 74
 075  public async Task StartAsync(CancellationToken cancellationToken) {
 076    await WaitForHealthyStatusAsync(cancellationToken);
 077  }
 78
 079  public Task StopAsync(CancellationToken cancellationToken) {
 080    throw new NotImplementedException();
 81  }
 82}