namespace ZB.MOM.WW.OtOpcUa.Cluster;
public sealed class AkkaClusterOptions
{
public const string SectionName = "Cluster";
/// Gets or sets the Akka system name.
public string SystemName { get; set; } = "otopcua";
/// Gets or sets the hostname to bind to (default 0.0.0.0).
public string Hostname { get; set; } = "0.0.0.0";
/// Gets or sets the port to listen on (default 4053).
public int Port { get; set; } = 4053;
///
/// Hostname advertised in cluster gossip. Must be reachable by other nodes.
/// In docker-compose this is the container DNS name; in bare metal it's the
/// host's stable LAN address.
///
public string PublicHostname { get; set; } = "127.0.0.1";
/// Gets or sets the seed nodes for cluster bootstrapping.
public string[] SeedNodes { get; set; } = Array.Empty();
///
/// Cluster roles for this node. When empty the role list comes from
/// OTOPCUA_ROLES via . Allowed values:
/// admin, driver, dev.
///
public string[] Roles { get; set; } = Array.Empty();
///
/// How the cluster decides to down a node it can no longer reach. One of auto-down
/// (default) or keep-oldest; any other value fails the host at startup.
///
///
///
/// auto-down — availability. The leader among the reachable members
/// downs the unreachable peer after
/// . A hard crash of either
/// node — including the oldest — fails over to the survivor with no operator action.
/// The trade is that a genuine network partition (both nodes alive, link cut) leaves
/// both sides running active until an operator restarts one.
///
///
/// keep-oldest — partition-safety. The SBR resolver sacrifices the younger
/// side of a split, so a partition can never run dual-active. The cost is severe for a
/// two-node pair: it cannot survive a crash of the oldest node at all. Akka.NET's
/// KeepOldest.OldestDecision only lets down-if-alone rescue a side holding
/// >= 2 members, so the 1-vs-1 survivor downs itself and shuts down — the
/// redundancy pair turns a single-node crash into a total outage. Choose this only for
/// clusters of three or more nodes, or where dual-active is genuinely worse than an
/// outage.
///
///
public string SplitBrainResolverStrategy { get; set; } = "auto-down";
///
/// Bootstrap self-form fallback window (decision 2026-07-22, scadaproj/akka_failover.md §6.1).
/// Akka only lets the FIRST listed seed form a new cluster; a non-first seed cold-starting
/// while its peer is down loops on InitJoin forever ("auto-down removes the crash outage,
/// not this one" — docs/Redundancy.md). When this node has waited longer than this window
/// without cluster membership it joins itself — but ONLY if its own address appears in
/// ; a non-seed node (e.g. a site node whose only seed is central-1)
/// stays waiting, because self-forming there creates a permanent island. Default 10s
/// (same-datacenter pair; a live peer answers InitJoin in milliseconds). null or a
/// non-positive value disables the fallback. Accepted trade: both pair nodes cold-starting
/// inside the window while mutually unreachable form two clusters — the same dual-active
/// class the auto-down strategy already accepts, same recovery (restart one side).
///
public TimeSpan? SelfFormAfter { get; set; } = TimeSpan.FromSeconds(10);
}