feat(health.akka): cluster health check with configurable status policy

This commit is contained in:
Joseph Doherty
2026-06-01 06:47:29 -04:00
parent 1ab2f32e8e
commit 25dd328280
4 changed files with 315 additions and 0 deletions
@@ -0,0 +1,51 @@
using Akka.Actor;
using Akka.Cluster;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Diagnostics.HealthChecks;
namespace ZB.MOM.WW.Health.Akka;
/// <summary>
/// Health check that maps the local node's Akka cluster membership status to a
/// <see cref="HealthStatus"/> through a configurable <see cref="AkkaClusterStatusPolicy"/>.
/// Register to the <see cref="ZbHealthTags.Ready"/> tag (recommended <c>[ready, active]</c>).
/// </summary>
/// <remarks>
/// The <see cref="ActorSystem"/> is resolved lazily from the service provider. If it is not yet
/// available — e.g. during startup before Akka is initialised — the check returns
/// <see cref="HealthStatus.Degraded"/> rather than throwing, so it is safe to register before Akka
/// is fully up.
/// </remarks>
public sealed class AkkaClusterHealthCheck : IHealthCheck
{
private readonly IServiceProvider _serviceProvider;
private readonly AkkaClusterStatusPolicy _policy;
/// <summary>Initializes a new <see cref="AkkaClusterHealthCheck"/>.</summary>
/// <param name="serviceProvider">
/// The application service provider. The <see cref="ActorSystem"/> is resolved lazily so the
/// check is startup-safe: if no <see cref="ActorSystem"/> is registered yet the result is Degraded.
/// </param>
/// <param name="policy">The status-to-health mapping policy to apply.</param>
public AkkaClusterHealthCheck(IServiceProvider serviceProvider, AkkaClusterStatusPolicy policy)
{
_serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));
_policy = policy ?? throw new ArgumentNullException(nameof(policy));
}
/// <inheritdoc />
public Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
var system = _serviceProvider.GetService<ActorSystem>();
if (system is null)
return Task.FromResult(HealthCheckResult.Degraded("ActorSystem not yet available."));
var status = Cluster.Get(system).SelfMember.Status;
var health = _policy.Evaluate(status);
var description = $"Akka cluster member status: {status}";
return Task.FromResult(new HealthCheckResult(health, description));
}
}