diff --git a/src/ZB.MOM.WW.ScadaBridge.Host/Actors/AkkaHostedService.cs b/src/ZB.MOM.WW.ScadaBridge.Host/Actors/AkkaHostedService.cs index c8f818ac..5f9a2930 100644 --- a/src/ZB.MOM.WW.ScadaBridge.Host/Actors/AkkaHostedService.cs +++ b/src/ZB.MOM.WW.ScadaBridge.Host/Actors/AkkaHostedService.cs @@ -201,6 +201,11 @@ public class AkkaHostedService : IHostedService /// rather than hard-coded, so the bound /// configuration value is actually consumed. /// + /// The split-brain-resolver downing-provider-class is installed + /// explicitly: Akka defaults to NoDowning, under which the entire + /// split-brain-resolver section is inert and singletons never migrate on a hard + /// crash or partition. Naming the SBR provider is what activates automatic downing. + /// /// Every duration is rendered via in /// milliseconds, so sub-second cluster timing values (e.g. a 750ms heartbeat) are /// preserved exactly instead of being rounded to whole seconds. @@ -251,6 +256,7 @@ akka {{ seed-nodes = [{seedNodesStr}] roles = [{rolesStr}] min-nr-of-members = {clusterOptions.MinNrOfMembers} + downing-provider-class = ""Akka.Cluster.SBR.SplitBrainResolverProvider, Akka.Cluster"" split-brain-resolver {{ active-strategy = {QuoteHocon(clusterOptions.SplitBrainResolverStrategy)} stable-after = {DurationHocon(clusterOptions.StableAfter)} diff --git a/tests/ZB.MOM.WW.ScadaBridge.Host.Tests/HoconBuilderTests.cs b/tests/ZB.MOM.WW.ScadaBridge.Host.Tests/HoconBuilderTests.cs index 85ba2606..b3b1b4ec 100644 --- a/tests/ZB.MOM.WW.ScadaBridge.Host.Tests/HoconBuilderTests.cs +++ b/tests/ZB.MOM.WW.ScadaBridge.Host.Tests/HoconBuilderTests.cs @@ -160,4 +160,22 @@ public class HoconBuilderTests TimeSpan.FromMilliseconds(7500), config.GetTimeSpan("akka.remote.transport-failure-detector.acceptable-heartbeat-pause")); } + + [Fact] + public void BuildHocon_EnablesSplitBrainResolverDowningProvider() + { + // Review 01 [Critical]: without downing-provider-class the entire + // split-brain-resolver section is inert (Akka default = NoDowning) and + // singletons never migrate on a hard crash. + var node = new NodeOptions { Role = "Central", NodeHostname = "node1", RemotingPort = 8081 }; + + var hocon = AkkaHostedService.BuildHocon( + node, DefaultCluster(), new[] { "Central" }, + TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(15)); + + var config = ConfigurationFactory.ParseString(hocon); + Assert.Equal( + "Akka.Cluster.SBR.SplitBrainResolverProvider, Akka.Cluster", + config.GetString("akka.cluster.downing-provider-class")); + } }