Files
git.stella-ops.org/src/AirGap/StellaOps.AirGap.Time/Health/TimeAnchorHealthCheck.cs
2026-02-04 19:59:20 +02:00

52 lines
1.8 KiB
C#

using Microsoft.Extensions.Diagnostics.HealthChecks;
using Microsoft.Extensions.Options;
using StellaOps.AirGap.Time.Models;
using StellaOps.AirGap.Time.Services;
namespace StellaOps.AirGap.Time.Health;
public sealed class TimeAnchorHealthCheck : IHealthCheck
{
private readonly TimeStatusService _statusService;
private readonly IOptions<AirGapOptions> _options;
private readonly TimeProvider _timeProvider;
public TimeAnchorHealthCheck(TimeStatusService statusService, IOptions<AirGapOptions> options, TimeProvider timeProvider)
{
_statusService = statusService;
_options = options;
_timeProvider = timeProvider;
}
public async Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
{
var opts = _options.Value;
var status = await _statusService.GetStatusAsync(opts.TenantId, _timeProvider.GetUtcNow(), cancellationToken).ConfigureAwait(false);
if (status.Anchor == TimeAnchor.Unknown)
{
return HealthCheckResult.Unhealthy("time-anchor-missing");
}
if (status.Staleness.IsBreach)
{
return HealthCheckResult.Unhealthy("time-anchor-stale");
}
IReadOnlyDictionary<string, object> data = new Dictionary<string, object>
{
["anchorDigest"] = status.Anchor.TokenDigest,
["ageSeconds"] = status.Staleness.AgeSeconds,
["warningSeconds"] = status.Staleness.WarningSeconds,
["breachSeconds"] = status.Staleness.BreachSeconds
};
if (status.Staleness.IsWarning)
{
return HealthCheckResult.Degraded("time-anchor-warning", data: data);
}
return HealthCheckResult.Healthy("time-anchor-healthy", data);
}
}