using Akka.Cluster; using ZB.MOM.WW.ScadaBridge.Host.Actors; using ZB.MOM.WW.ScadaBridge.InboundAPI; namespace ZB.MOM.WW.ScadaBridge.Host.Health; /// /// InboundAPI-008 / InboundAPI-022: production implementation of /// backed by the running Akka.NET cluster. /// /// The inbound API is "Central cluster only (active node)" — a standby central /// node must not execute method scripts or Route.To() calls. This gate /// mirrors the leadership check in (the /// node is the cluster leader, ), so /// can return HTTP 503 on a standby. /// /// Registered only in the Central-role branch of Program.cs. The gate /// is resolved per request from HttpContext.RequestServices; while the /// AkkaHostedService is still warming up (ActorSystem == null) /// or the node has not yet reached , this /// implementation reports IsActiveNode == false — the safe-by-default /// answer matching the standby case. /// public sealed class ActiveNodeGate : IActiveNodeGate { private readonly AkkaHostedService _akkaService; /// Initializes a new bound to the given Akka hosted service. /// The Akka hosted service exposing the cluster's . public ActiveNodeGate(AkkaHostedService akkaService) { _akkaService = akkaService; } /// /// true only when this node has joined the cluster () /// AND is the current cluster leader; false in every other state /// (actor system not yet started, node still joining, node is a standby). /// public bool IsActiveNode { get { var system = _akkaService.ActorSystem; if (system == null) return false; var cluster = Cluster.Get(system); var self = cluster.SelfMember; if (self.Status != MemberStatus.Up) return false; var leader = cluster.State.Leader; return leader != null && leader == self.Address; } } }