43 lines
1.7 KiB
C#
43 lines
1.7 KiB
C#
using Akka.Cluster;
|
|
|
|
namespace ZB.MOM.WW.ScadaBridge.Host.Health;
|
|
|
|
/// <summary>
|
|
/// THE single definition of "active node" (review 01 [High]): a node is active
|
|
/// when it is the OLDEST Up member (optionally within a role scope) — i.e. the
|
|
/// member the ClusterSingletonManager places singletons on. Cluster LEADERSHIP
|
|
/// (lowest address) is an Akka-internal concept that diverges from singleton
|
|
/// placement permanently once the original first node restarts and rejoins;
|
|
/// every product-level active/standby decision must use this evaluator, never
|
|
/// cluster.State.Leader.
|
|
/// </summary>
|
|
public static class ClusterActivityEvaluator
|
|
{
|
|
/// <summary>True when self is Up and no other Up member (in the role scope) is older.</summary>
|
|
public static bool SelfIsOldest(Cluster cluster, string? role = null)
|
|
{
|
|
var self = cluster.SelfMember;
|
|
if (self.Status != MemberStatus.Up)
|
|
return false;
|
|
if (role != null && !self.HasRole(role))
|
|
return false;
|
|
|
|
return cluster.State.Members
|
|
.Where(m => m.Status == MemberStatus.Up)
|
|
.Where(m => role == null || m.HasRole(role))
|
|
.All(m => m.UniqueAddress.Equals(self.UniqueAddress) || self.IsOlderThan(m));
|
|
}
|
|
|
|
/// <summary>The oldest Up member in the role scope, or null while none is Up. Used for Primary/Standby labelling.</summary>
|
|
public static Member? OldestUpMember(Cluster cluster, string? role = null)
|
|
{
|
|
Member? oldest = null;
|
|
foreach (var m in cluster.State.Members.Where(m => m.Status == MemberStatus.Up))
|
|
{
|
|
if (role != null && !m.HasRole(role)) continue;
|
|
if (oldest == null || m.IsOlderThan(oldest)) oldest = m;
|
|
}
|
|
return oldest;
|
|
}
|
|
}
|