docs(archreview #11): correct Critical 1 premise — SBR was already active on master, not NoDowning
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.
This commit is contained in:
+17
-12
@@ -154,23 +154,28 @@ Node A lists Node B's `ApplicationUri` and vice-versa. Validated by `DualEndpoin
|
||||
|
||||
## Split-brain
|
||||
|
||||
The split-brain resolver is **activated in code** by the typed `ClusterOptions.SplitBrainResolver`
|
||||
(`KeepOldestOption { DownIfAlone = true }`) set in
|
||||
`ServiceCollectionExtensions.BuildClusterOptions` — this is what registers
|
||||
`Akka.Cluster.SBR.SplitBrainResolverProvider`. **Without that typed registration the `split-brain-resolver`
|
||||
HOCON block in `akka.conf` is inert and the cluster runs Akka's default `NoDowning`**, meaning a
|
||||
hard-crashed node is never downed and neither the cluster singletons nor the `driver` role-leader ever fail
|
||||
over (a partition would leave both redundancy sides at ServiceLevel 240 indefinitely). The HOCON block is the
|
||||
tuning source only: `active-strategy = keep-oldest`, `stable-after = 15s`, `keep-oldest.down-if-alone = on`,
|
||||
`failure-detector.threshold = 10.0` (its `active-strategy` + `down-if-alone` must stay consistent with the
|
||||
typed option; `stable-after` lives only in HOCON because the typed option can't express it).
|
||||
The split-brain resolver is **active by default**: Akka.Cluster.Hosting's `WithClustering` enables an SBR
|
||||
downing provider whenever `ClusterOptions.SplitBrainResolver` is null (it applies
|
||||
`SplitBrainResolverOption.Default`, which registers `Akka.Cluster.SBR.SplitBrainResolverProvider`), and that
|
||||
provider reads the `split-brain-resolver` HOCON block in `akka.conf`. On top of that,
|
||||
`ServiceCollectionExtensions.BuildClusterOptions` sets the typed `ClusterOptions.SplitBrainResolver`
|
||||
(`KeepOldestOption { DownIfAlone = true }`) to make the strategy **explicit in code** rather than relying on
|
||||
the framework default — it is reinforcing, not the sole activator, and yields the same effective behavior. So
|
||||
the cluster is **not** running `NoDowning`; hard-crashed nodes are downed and both the cluster singletons and
|
||||
the `driver` role-leader fail over. (Only an *explicit* `NoDowning`, e.g.
|
||||
`akka.cluster.downing-provider-class = ""`, would leave both redundancy sides at ServiceLevel 240
|
||||
indefinitely.) The HOCON block carries the tuning: `active-strategy = keep-oldest`, `stable-after = 15s`,
|
||||
`keep-oldest.down-if-alone = on`, `failure-detector.threshold = 10.0` (its `active-strategy` + `down-if-alone`
|
||||
must stay consistent with the typed option; `stable-after` lives only in HOCON because the typed option can't
|
||||
express it).
|
||||
|
||||
`keep-oldest` is the correct strategy for a 2-node warm-redundancy pair: under a clean partition the oldest
|
||||
member (typically the long-running primary) stays up and the smaller (or younger) side downs itself within
|
||||
~`stable-after` seconds; `down-if-alone` downs a node that loses its only peer. `keep-majority`/`static-quorum`
|
||||
are wrong for two nodes (no majority in a 1-1 split). The `RedundancyStateActor` on the surviving partition
|
||||
re-computes from the post-partition `Cluster.State`, and a hard-crashed (not gracefully stopped) node now
|
||||
triggers the same failover.
|
||||
re-computes from the post-partition `Cluster.State`, and a hard-crashed (not gracefully stopped) node
|
||||
triggers the same failover — verified by `HardKillFailoverTests` (its negative control confirms failover
|
||||
survives removing the typed option, and only breaks under an explicit `NoDowning`).
|
||||
|
||||
There is no operator-driven role swap during a partition. Failover is what the cluster does automatically.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user