0a85a839a2
Add ActiveNodeHealthCheck that returns 200 only on the Akka.NET cluster leader, enabling Traefik to route traffic to the active central node and automatically fail over when the leader changes. Also fixes AkkaClusterHealthCheck to resolve ActorSystem from AkkaHostedService (was always null via DI).
41 lines
1.4 KiB
C#
41 lines
1.4 KiB
C#
using Akka.Cluster;
|
|
using Microsoft.Extensions.Diagnostics.HealthChecks;
|
|
using ScadaLink.Host.Actors;
|
|
|
|
namespace ScadaLink.Host.Health;
|
|
|
|
/// <summary>
|
|
/// Health check that returns healthy only if this node is the active (leader) node
|
|
/// in the Akka.NET cluster. Used by Traefik to route traffic to the active node.
|
|
/// </summary>
|
|
public class ActiveNodeHealthCheck : IHealthCheck
|
|
{
|
|
private readonly AkkaHostedService _akkaService;
|
|
|
|
public ActiveNodeHealthCheck(AkkaHostedService akkaService)
|
|
{
|
|
_akkaService = akkaService;
|
|
}
|
|
|
|
public Task<HealthCheckResult> CheckHealthAsync(
|
|
HealthCheckContext context,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var system = _akkaService.ActorSystem;
|
|
if (system == null)
|
|
return Task.FromResult(HealthCheckResult.Unhealthy("ActorSystem not yet available."));
|
|
|
|
var cluster = Cluster.Get(system);
|
|
var self = cluster.SelfMember;
|
|
|
|
if (self.Status != MemberStatus.Up)
|
|
return Task.FromResult(HealthCheckResult.Unhealthy($"Node not Up (status: {self.Status})."));
|
|
|
|
var leader = cluster.State.Leader;
|
|
if (leader != null && leader == self.Address)
|
|
return Task.FromResult(HealthCheckResult.Healthy("Active node (cluster leader)."));
|
|
|
|
return Task.FromResult(HealthCheckResult.Unhealthy("Standby node (not cluster leader)."));
|
|
}
|
|
}
|