eaf78aad90
Akka.Cluster.Hosting's WithClustering enables an SBR downing provider by default (applies SplitBrainResolverOption.Default when ClusterOptions.SplitBrainResolver is null), which reads the pre-existing akka.conf keep-oldest block. So the cluster was NOT running NoDowning before Critical 1 and hard-crash failover already worked — the typed KeepOldestOption is reinforcing/explicit-in-code, not the sole activator. Corrects the inaccurate 'HOCON inert / NoDowning / never fails over' framing in: - ServiceCollectionExtensions.BuildClusterOptions XML comment - akka.conf split-brain-resolver comment - docs/Redundancy.md Split-brain section - SplitBrainResolverActivationTests summary + assertion message (+ method rename) No code revert (the typed option is correct belt-and-suspenders). Cluster.Tests 29/29. Surfaced by the #9 hard-kill failover negative control.
59 lines
2.6 KiB
C#
59 lines
2.6 KiB
C#
using Akka.Cluster.Hosting;
|
|
using Akka.Cluster.Hosting.SBR;
|
|
using Shouldly;
|
|
using Xunit;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Cluster.Tests;
|
|
|
|
/// <summary>
|
|
/// Guards that the split-brain-resolver strategy stays set <b>explicitly in code</b> (arch-review 03/S1,
|
|
/// premise corrected — see #11). Akka.Cluster.Hosting already enables an SBR downing provider by default
|
|
/// (it applies <c>SplitBrainResolverOption.Default</c> when <see cref="ClusterOptions.SplitBrainResolver"/>
|
|
/// is null, which reads the akka.conf <c>keep-oldest</c> block), so the cluster is not NoDowning even
|
|
/// without the typed option. These tests assert
|
|
/// <see cref="ServiceCollectionExtensions.BuildClusterOptions"/> sets the typed
|
|
/// <c>KeepOldestOption { DownIfAlone = true }</c> so the strategy is explicit in code rather than relying on
|
|
/// the framework default — a future refactor cannot silently drop that explicitness. (Failover behaviour is
|
|
/// separately verified by <c>HardKillFailoverTests</c>, which passes regardless of activation path.)
|
|
/// </summary>
|
|
public sealed class SplitBrainResolverActivationTests
|
|
{
|
|
private static AkkaClusterOptions SampleOptions() => new()
|
|
{
|
|
SeedNodes = new[] { "akka.tcp://otopcua@127.0.0.1:4053" },
|
|
Roles = new[] { "admin", "driver" },
|
|
};
|
|
|
|
/// <summary>Verifies the cluster options carry an explicit split-brain resolver strategy.</summary>
|
|
[Fact]
|
|
public void BuildClusterOptions_sets_an_explicit_split_brain_resolver()
|
|
{
|
|
var options = ServiceCollectionExtensions.BuildClusterOptions(SampleOptions());
|
|
|
|
options.SplitBrainResolver.ShouldNotBeNull(
|
|
"SplitBrainResolver must be set explicitly in code — keeps the strategy independent of Akka.Cluster.Hosting's default provider rather than relying on it.");
|
|
}
|
|
|
|
/// <summary>Verifies the resolver is keep-oldest with down-if-alone (correct for a 2-node pair).</summary>
|
|
[Fact]
|
|
public void BuildClusterOptions_uses_keep_oldest_with_down_if_alone()
|
|
{
|
|
var options = ServiceCollectionExtensions.BuildClusterOptions(SampleOptions());
|
|
|
|
var keepOldest = options.SplitBrainResolver.ShouldBeOfType<KeepOldestOption>();
|
|
keepOldest.DownIfAlone.ShouldBe(true);
|
|
}
|
|
|
|
/// <summary>Verifies seed nodes and roles are still threaded through unchanged.</summary>
|
|
[Fact]
|
|
public void BuildClusterOptions_preserves_seed_nodes_and_roles()
|
|
{
|
|
var input = SampleOptions();
|
|
|
|
var options = ServiceCollectionExtensions.BuildClusterOptions(input);
|
|
|
|
options.SeedNodes.ShouldBe(input.SeedNodes);
|
|
options.Roles.ShouldBe(input.Roles);
|
|
}
|
|
}
|