using Akka.Actor; using Microsoft.Extensions.Diagnostics.HealthChecks; namespace ZB.MOM.WW.ScadaBridge.Host.Health; /// /// /health/active check: Healthy only on the oldest Up member — the node that /// hosts the cluster singletons. Replaces the shared package's leader-based /// ActiveNodeHealthCheck (review 01 [High]): leadership is address-ordered and /// diverges from singleton placement after a restart, and during a partition /// BOTH nodes compute themselves leader, so Traefik served both. Oldest-member /// semantics keep exactly one active node through a partition (the non-oldest /// side still sees the old oldest member until SBR resolves membership). /// public sealed class OldestNodeActiveHealthCheck : IHealthCheck { private readonly ActorSystem _system; /// Initializes a new bound to the running actor system. /// The live cluster actor system. public OldestNodeActiveHealthCheck(ActorSystem system) => _system = system; /// public Task CheckHealthAsync(HealthCheckContext context, CancellationToken ct = default) { var cluster = Akka.Cluster.Cluster.Get(_system); return Task.FromResult(ClusterActivityEvaluator.SelfIsOldest(cluster) ? HealthCheckResult.Healthy("oldest Up member (singleton host)") : HealthCheckResult.Unhealthy("not the oldest Up member (standby)")); } }