From 9215e9bb47b7ab9abce99a6745a3f19801968636 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Thu, 30 Mar 2023 11:43:03 -0500 Subject: [PATCH 01/16] enable `keep-majority` default SBR Enables `keep-majority` as the default SBR and turns it on by default for Akka.Cluster. This was a planned change for Akka.NET v1.5.0 but we didn't implement it. --- src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs | 8 ++++++++ src/core/Akka.Cluster/Configuration/Cluster.conf | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs b/src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs index b57539104cf..6ca0c300a0f 100644 --- a/src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs +++ b/src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Immutable; using Akka.Actor; +using Akka.Cluster.SBR; using Akka.Configuration; using Akka.Dispatch; using Akka.Remote; @@ -71,6 +72,13 @@ public void Clustering_must_be_able_to_parse_generic_cluster_config_elements() settings.VerboseHeartbeatLogging.Should().BeFalse(); settings.VerboseGossipReceivedLogging.Should().BeFalse(); settings.RunCoordinatedShutdownWhenDown.Should().BeTrue(); + + // downing provider settings + settings.DowningProviderType.Should().Be(); + var sbrSettings = new SplitBrainResolverSettings(Sys.Settings.Config); + sbrSettings.DowningStableAfter.Should().Be(20.Seconds()); + sbrSettings.DownAllWhenUnstable.Should().Be(15.Seconds()); // 3/4 OF DowningStableAfter + sbrSettings.DowningStrategy.Should().Be("keep-majority"); } /// diff --git a/src/core/Akka.Cluster/Configuration/Cluster.conf b/src/core/Akka.Cluster/Configuration/Cluster.conf index 261ff2ae93a..56b09b9e2ed 100644 --- a/src/core/Akka.Cluster/Configuration/Cluster.conf +++ b/src/core/Akka.Cluster/Configuration/Cluster.conf @@ -63,7 +63,9 @@ akka { # `Akka.Cluster.IDowningProvider` having two argument constructor: # - argument 1: accepting an `ActorSystem` # - argument 2: accepting an `Akka.Cluster.Cluster` - downing-provider-class = "" + downing-provider-class = "Akka.Cluster.SBR.SplitBrainResolverProvider, Akka.Cluster" + + # If this is set to "off", the leader will not move 'Joining' members to 'Up' during a network # split. This feature allows the leader to accept 'Joining' members to be 'WeaklyUp' From e9b08c249f6e8b3f1e15bcff48da19763f6b8f90 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Tue, 4 Apr 2023 14:30:40 -0500 Subject: [PATCH 02/16] added upgrade advisories to documentation and some spec / warning fixes --- .../clustering/split-brain-resolver.md | 8 ++++- .../akkadotnet-v1.5-upgrade-advisories.md | 32 +++++++++++++++++++ .../Akka.Cluster.Tests/DowningProviderSpec.cs | 8 ++--- src/core/Akka.Cluster/AutoDown.cs | 3 ++ src/core/Akka.Cluster/Cluster.cs | 24 ++++++++++---- src/core/Akka.Cluster/ClusterSettings.cs | 17 ++++------ .../Akka.Cluster/Configuration/Cluster.conf | 8 ----- .../SBR/SplitBrainResolverSettings.cs | 24 +++++++------- 8 files changed, 81 insertions(+), 43 deletions(-) diff --git a/docs/articles/clustering/split-brain-resolver.md b/docs/articles/clustering/split-brain-resolver.md index 9a1487ed4c1..7e98b7ce52a 100644 --- a/docs/articles/clustering/split-brain-resolver.md +++ b/docs/articles/clustering/split-brain-resolver.md @@ -38,6 +38,9 @@ Keep in mind that split brain resolver will NOT work when `akka.cluster.auto-dow Beginning in Akka.NET v1.4.16, the Akka.NET project has ported the original split brain resolver implementations from Lightbend as they are now open source. The following section of documentation describes how Akka.NET's hand-rolled split brain resolvers are implemented. +> [!IMPORTANT] +> As of Akka.NET v1.5.2, the `keep-majority` split brain resolution strategy is now enabled by default. This should be acceptable for the majority of Akka.Cluster users, but please read on. + ### Picking a Strategy In order to enable an Akka.NET split brain resolver in your cluster (they are not enabled by default), you will want to update your `akka.cluster` HOCON configuration to the following: @@ -59,7 +62,7 @@ This will cause the [`Akka.Cluster.SBR.SplitBrainResolverProvider`](xref:Akka.Cl The following strategies are supported: * `static-quorum` -* `keep-majority` +* `keep-majority` **(default)** * `keep-oldest` * `down-all` * `lease-majority` @@ -144,6 +147,9 @@ akka.cluster.split-brain-resolver { #### Keep Majority +> [!NOTE] +> `keep-majority` is the default SBR strategy for Akka.Cluster as of Akka.NET v1.5.2+. + The `keep-majority` strategy will down this part of the cluster, which sees a lesser part of the whole cluster. This choice is made based on the latest known state of the cluster. When cluster will split into two equal parts, the one which contains the lowest address, will survive. When to use it? When your cluster can grow or shrink very dynamically. diff --git a/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md b/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md index 935659134a4..d35756a6a88 100644 --- a/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md +++ b/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md @@ -11,6 +11,38 @@ This document contains specific upgrade suggestions, warnings, and notices that +## Upgrading to Akka.NET v1.5.2 + +Akka.NET v1.5.2 introduces two important behavioral changes: + +* [Akka.Persistence: need to remove hard-coded Newtonsoft.Json `object` serializer](https://github.com/akkadotnet/akka.net/issues/6389) +* [Akka.Cluster: enable `keep-majority` as default Split Brain Resolver](https://github.com/akkadotnet/akka.net/pull/6628) + +We meant to include both of these changes in Akka.NET v1.5.0 but simply ran out of time before making them into that release. + +### Akka.Persistence Changes + +The impact of [Akka.Persistence: need to remove hard-coded Newtonsoft.Json `object` serializer](https://github.com/akkadotnet/akka.net/issues/6389) is pretty minor: all versions of Akka.NET prior to 1.5.2 used Newtonsoft.Json as the `object` serializer for Akka.Persistence regardless of whether or not you [used a custom `object` serializer, such as Hyperion](xref:serialization#complex-object-serialization-using-hyperion). + +Going forward your user-defined `object` serialization binding will now be respected by Akka.Persistence. Any old data previously saved using Newtonsoft.Json will continue to be recovered automatically by Newtonsoft.Json - it's only the serialziation of new objects inserted after upgrading to v1.5.2 that will be affected. + +If you _never changed your `object`_ serializer (most users don't) then this change doesn't affect you. + +### Akka.Cluster Split Brain Resolver Changes + +As of Akka.NET v1.5.2 we've now enabled the `keep-majority` [Split Brain Resolver](xref:split-brain-resolver) by default. + +If you were already running with a custom SBR enabled, this change won't affect you. + +If you weren't running with an SBR enabled, you should read the [Akka.Cluster Split Brain Resolver documentation](xref:split-brain-resolver). + +Also worth noting: we've disabled the `akka.cluster.auto-down-unreachable-after` setting as it's always been a poor and shoddy way to manage network partitions inside Akka.Cluster. If you have that seting enabled it will be ignored and you'll see the following warning appear instead: + +```shell +The `auto-down-unreachable-after` feature has been deprecated as of Akka.NET v1.5.2 and will be removed in a future version of Akka.NET. +The `keep-majority` split brain resolver will be used instead. See https://getakka.net/articles/cluster/split-brain-resolver.html for more details. +``` + ## Upgrading From Akka.NET v1.4 to v1.5 In case you need help upgrading: diff --git a/src/core/Akka.Cluster.Tests/DowningProviderSpec.cs b/src/core/Akka.Cluster.Tests/DowningProviderSpec.cs index 0c923e36c95..4cd0cbfc0c0 100644 --- a/src/core/Akka.Cluster.Tests/DowningProviderSpec.cs +++ b/src/core/Akka.Cluster.Tests/DowningProviderSpec.cs @@ -69,21 +69,21 @@ public class DowningProviderSpec : AkkaSpec "); [Fact] - public void Downing_provider_should_default_to_NoDowning() + public void Downing_provider_should_default_to_KeepMajority() { using (var system = ActorSystem.Create("default", BaseConfig)) { - Cluster.Get(system).DowningProvider.Should().BeOfType(); + Cluster.Get(system).DowningProvider.Should().BeOfType(); } } [Fact] - public void Downing_provider_should_use_AutoDowning_if_auto_down_unreachable_after_is_configured() + public void Downing_provider_should_ignore_AutoDowning_if_auto_down_unreachable_after_is_configured() { var config = ConfigurationFactory.ParseString(@"akka.cluster.auto-down-unreachable-after=18s"); using (var system = ActorSystem.Create("auto-downing", config.WithFallback(BaseConfig))) { - Cluster.Get(system).DowningProvider.Should().BeOfType(); + Cluster.Get(system).DowningProvider.Should().BeOfType(); } } diff --git a/src/core/Akka.Cluster/AutoDown.cs b/src/core/Akka.Cluster/AutoDown.cs index 240618a321a..a1e5ceb476d 100644 --- a/src/core/Akka.Cluster/AutoDown.cs +++ b/src/core/Akka.Cluster/AutoDown.cs @@ -270,6 +270,7 @@ private void Remove(UniqueAddress node) /// /// Used when no custom provider is configured and 'auto-down-unreachable-after' is enabled. /// + [Obsolete("No longer used as of Akka.NET v1.5.2")] public sealed class AutoDowning : IDowningProvider { private readonly ActorSystem _system; @@ -296,7 +297,9 @@ public Props DowningActorProps { get { +#pragma warning disable CS0618 // disable obsolete warning here because this entire class is obsolete var autoDownUnreachableAfter = _cluster.Settings.AutoDownUnreachableAfter; +#pragma warning restore CS0618 if (!autoDownUnreachableAfter.HasValue) throw new ConfigurationException("AutoDowning downing provider selected but 'akka.cluster.auto-down-unreachable-after' not set"); diff --git a/src/core/Akka.Cluster/Cluster.cs b/src/core/Akka.Cluster/Cluster.cs index 9c7661a5fee..e4a8a73908c 100644 --- a/src/core/Akka.Cluster/Cluster.cs +++ b/src/core/Akka.Cluster/Cluster.cs @@ -67,13 +67,11 @@ static Cluster() bool GetAssertInvariants() { var isOn = Environment.GetEnvironmentVariable("AKKA_CLUSTER_ASSERT")?.ToLowerInvariant(); - switch (isOn) + return isOn switch { - case "on": - return true; - default: - return false; - } + "on" => true, + _ => false + }; } IsAssertInvariantsEnabled = GetAssertInvariants(); @@ -114,12 +112,24 @@ public Cluster(ActorSystemImpl system) System = system; Settings = new ClusterSettings(system.Settings.Config, system.Name); - if (!(system.Provider is IClusterActorRefProvider provider)) + if (system.Provider is not IClusterActorRefProvider provider) throw new ConfigurationException( $"ActorSystem {system} needs to have a 'IClusterActorRefProvider' enabled in the configuration, currently uses {system.Provider.GetType().FullName}"); SelfUniqueAddress = new UniqueAddress(provider.Transport.DefaultAddress, AddressUidExtension.Uid(system)); _log = Logging.GetLogger(system, "Cluster"); + + // log a warning if the user has set auto-down-unreachable-after to any value other than "off" + // obsolete setting, so suppress obsolete warning +#pragma warning disable CS0618 + if (Settings.AutoDownUnreachableAfter != null) +#pragma warning restore CS0618 + { + _log.Warning( + "The `auto-down-unreachable-after` feature has been deprecated as of Akka.NET v1.5.2 and will be removed in a future version of Akka.NET. " + + "The `keep-majority` split brain resolver will be used instead. See https://getakka.net/articles/cluster/split-brain-resolver.html for more details."); + } + CurrentInfoLogger = new InfoLogger(_log, Settings, SelfAddress); diff --git a/src/core/Akka.Cluster/ClusterSettings.cs b/src/core/Akka.Cluster/ClusterSettings.cs index 76d5bf8ce44..cb946b93f51 100644 --- a/src/core/Akka.Cluster/ClusterSettings.cs +++ b/src/core/Akka.Cluster/ClusterSettings.cs @@ -22,8 +22,8 @@ namespace Akka.Cluster /// public sealed class ClusterSettings { - readonly Config _failureDetectorConfig; - readonly string _useDispatcher; + private readonly Config _failureDetectorConfig; + private readonly string _useDispatcher; /// /// Initializes a new instance of the class. @@ -87,16 +87,10 @@ public ClusterSettings(Config config, string systemName) VerboseGossipReceivedLogging = clusterConfig.GetBoolean("debug.verbose-receive-gossip-logging", false); var downingProviderClassName = clusterConfig.GetString("downing-provider-class", null); - if (!string.IsNullOrEmpty(downingProviderClassName)) - DowningProviderType = Type.GetType(downingProviderClassName, true); - else if (AutoDownUnreachableAfter.HasValue) - DowningProviderType = typeof(AutoDowning); - else - DowningProviderType = typeof(NoDowning); + DowningProviderType = !string.IsNullOrEmpty(downingProviderClassName) ? Type.GetType(downingProviderClassName, true) : typeof(NoDowning); RunCoordinatedShutdownWhenDown = clusterConfig.GetBoolean("run-coordinated-shutdown-when-down", false); - - // TODO: replace with a switch expression when we upgrade to C#8 or later + TimeSpan GetWeaklyUpDuration() { var cKey = "allow-weakly-up-members"; @@ -207,8 +201,9 @@ TimeSpan GetWeaklyUpDuration() public TimeSpan? PublishStatsInterval { get; } /// - /// TBD + /// Obsolete. No longer used as of Akka.NET v1.5. /// + [Obsolete(message:"No longer used as of Akka.NET v1.5.2 - clustering defaults to using KeepMajority SBR instead")] public TimeSpan? AutoDownUnreachableAfter { get; } /// diff --git a/src/core/Akka.Cluster/Configuration/Cluster.conf b/src/core/Akka.Cluster/Configuration/Cluster.conf index 56b09b9e2ed..7d3df6e29bc 100644 --- a/src/core/Akka.Cluster/Configuration/Cluster.conf +++ b/src/core/Akka.Cluster/Configuration/Cluster.conf @@ -35,14 +35,6 @@ akka { # attempts. shutdown-after-unsuccessful-join-seed-nodes = off - # Should the 'leader' in the cluster be allowed to automatically mark - # unreachable nodes as DOWN after a configured time of unreachability? - # Using auto-down implies that two separate clusters will automatically be - # formed in case of network partition. - # Disable with "off" or specify a duration to enable auto-down. - # If a downing-provider-class is configured this setting is ignored. - auto-down-unreachable-after = off - # Time margin after which shards or singletons that belonged to a downed/removed # partition are created in surviving partition. The purpose of this margin is that # in case of a network partition the persistent actors in the non-surviving partitions diff --git a/src/core/Akka.Cluster/SBR/SplitBrainResolverSettings.cs b/src/core/Akka.Cluster/SBR/SplitBrainResolverSettings.cs index 5e2b4113c8a..52f73f70075 100644 --- a/src/core/Akka.Cluster/SBR/SplitBrainResolverSettings.cs +++ b/src/core/Akka.Cluster/SBR/SplitBrainResolverSettings.cs @@ -23,10 +23,10 @@ public sealed class SplitBrainResolverSettings public static readonly ImmutableHashSet AllStrategyNames = ImmutableHashSet.Create(KeepMajorityName, LeaseMajorityName, StaticQuorumName, KeepOldestName, DownAllName); - private readonly Lazy lazyKeepMajorityRole; - private readonly Lazy lazyKeepOldestSettings; - private readonly Lazy lazyLeaseMajoritySettings; - private readonly Lazy lazyStaticQuorumSettings; + private readonly Lazy _lazyKeepMajorityRole; + private readonly Lazy _lazyKeepOldestSettings; + private readonly Lazy _lazyLeaseMajoritySettings; + private readonly Lazy _lazyStaticQuorumSettings; public SplitBrainResolverSettings(Config config) { @@ -82,9 +82,9 @@ string Role(Config c) return r; } - lazyKeepMajorityRole = new Lazy(() => { return Role(StrategyConfig(KeepMajorityName)); }); + _lazyKeepMajorityRole = new Lazy(() => { return Role(StrategyConfig(KeepMajorityName)); }); - lazyStaticQuorumSettings = new Lazy(() => + _lazyStaticQuorumSettings = new Lazy(() => { var c = StrategyConfig(StaticQuorumName); var size = c.GetInt("quorum-size"); @@ -95,7 +95,7 @@ string Role(Config c) return new StaticQuorumSettings(size, Role(c)); }); - lazyKeepOldestSettings = new Lazy(() => + _lazyKeepOldestSettings = new Lazy(() => { var c = StrategyConfig(KeepOldestName); var downIfAlone = c.GetBoolean("down-if-alone"); @@ -103,7 +103,7 @@ string Role(Config c) return new KeepOldestSettings(downIfAlone, Role(c)); }); - lazyLeaseMajoritySettings = new Lazy(() => + _lazyLeaseMajoritySettings = new Lazy(() => { var c = StrategyConfig(LeaseMajorityName); var leaseImplementation = c.GetString("lease-implementation"); @@ -129,13 +129,13 @@ string Role(Config c) public TimeSpan DownAllWhenUnstable { get; } - public string KeepMajorityRole => lazyKeepMajorityRole.Value; + public string KeepMajorityRole => _lazyKeepMajorityRole.Value; - public StaticQuorumSettings StaticQuorumSettings => lazyStaticQuorumSettings.Value; + public StaticQuorumSettings StaticQuorumSettings => _lazyStaticQuorumSettings.Value; - public KeepOldestSettings KeepOldestSettings => lazyKeepOldestSettings.Value; + public KeepOldestSettings KeepOldestSettings => _lazyKeepOldestSettings.Value; - public LeaseMajoritySettings LeaseMajoritySettings => lazyLeaseMajoritySettings.Value; + public LeaseMajoritySettings LeaseMajoritySettings => _lazyLeaseMajoritySettings.Value; } public sealed class StaticQuorumSettings From 37821325495e5f2cdd577b5f054ad3b73016d78d Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Tue, 4 Apr 2023 14:34:31 -0500 Subject: [PATCH 03/16] fixed typos --- .../whats-new/akkadotnet-v1.5-upgrade-advisories.md | 4 ++-- src/core/Akka.Cluster/ClusterDaemon.cs | 5 ----- src/core/Akka.Cluster/ClusterSettings.cs | 2 ++ 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md b/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md index d35756a6a88..5bb6ce5857d 100644 --- a/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md +++ b/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md @@ -24,7 +24,7 @@ We meant to include both of these changes in Akka.NET v1.5.0 but simply ran out The impact of [Akka.Persistence: need to remove hard-coded Newtonsoft.Json `object` serializer](https://github.com/akkadotnet/akka.net/issues/6389) is pretty minor: all versions of Akka.NET prior to 1.5.2 used Newtonsoft.Json as the `object` serializer for Akka.Persistence regardless of whether or not you [used a custom `object` serializer, such as Hyperion](xref:serialization#complex-object-serialization-using-hyperion). -Going forward your user-defined `object` serialization binding will now be respected by Akka.Persistence. Any old data previously saved using Newtonsoft.Json will continue to be recovered automatically by Newtonsoft.Json - it's only the serialziation of new objects inserted after upgrading to v1.5.2 that will be affected. +Going forward your user-defined `object` serialization binding will now be respected by Akka.Persistence. Any old data previously saved using Newtonsoft.Json will continue to be recovered automatically by Newtonsoft.Json - it's only the serialization of new objects inserted after upgrading to v1.5.2 that will be affected. If you _never changed your `object`_ serializer (most users don't) then this change doesn't affect you. @@ -36,7 +36,7 @@ If you were already running with a custom SBR enabled, this change won't affect If you weren't running with an SBR enabled, you should read the [Akka.Cluster Split Brain Resolver documentation](xref:split-brain-resolver). -Also worth noting: we've disabled the `akka.cluster.auto-down-unreachable-after` setting as it's always been a poor and shoddy way to manage network partitions inside Akka.Cluster. If you have that seting enabled it will be ignored and you'll see the following warning appear instead: +Also worth noting: we've disabled the `akka.cluster.auto-down-unreachable-after` setting as it's always been a poor and shoddy way to manage network partitions inside Akka.Cluster. If you have that setting enabled it will be ignored and you'll see the following warning appear instead: ```shell The `auto-down-unreachable-after` feature has been deprecated as of Akka.NET v1.5.2 and will be removed in a future version of Akka.NET. diff --git a/src/core/Akka.Cluster/ClusterDaemon.cs b/src/core/Akka.Cluster/ClusterDaemon.cs index 21c255e1489..89a8ef81f9a 100644 --- a/src/core/Akka.Cluster/ClusterDaemon.cs +++ b/src/core/Akka.Cluster/ClusterDaemon.cs @@ -285,11 +285,6 @@ internal class JoinSeenNode /// internal class InitJoin : IClusterMessage, IDeadLetterSuppression { - /// - public override bool Equals(object obj) - { - return obj is InitJoin; - } } /// diff --git a/src/core/Akka.Cluster/ClusterSettings.cs b/src/core/Akka.Cluster/ClusterSettings.cs index cb946b93f51..79e3b469fac 100644 --- a/src/core/Akka.Cluster/ClusterSettings.cs +++ b/src/core/Akka.Cluster/ClusterSettings.cs @@ -66,7 +66,9 @@ public ClusterSettings(Config config, string systemName) ) ? TimeSpan.Zero : clusterConfig.GetTimeSpan("down-removal-margin", null); +#pragma warning disable CS0618 AutoDownUnreachableAfter = clusterConfig.GetTimeSpanWithOffSwitch("auto-down-unreachable-after"); +#pragma warning restore CS0618 Roles = clusterConfig.GetStringList("roles", new string[] { }).ToImmutableHashSet(); AppVersion = Util.AppVersion.Create(clusterConfig.GetString("app-version")); From 7ca8104f77a2f3aaf75e2a2ac33617d6bfd13709 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Tue, 4 Apr 2023 14:45:29 -0500 Subject: [PATCH 04/16] added documentation on how to disable the default downing provider --- docs/articles/clustering/split-brain-resolver.md | 10 ++++++++++ .../whats-new/akkadotnet-v1.5-upgrade-advisories.md | 10 ++++++++++ .../Singleton/ClusterSingletonConfigSpec.cs | 2 +- .../Akka.Cluster.TestKit/MultiNodeClusterSpec.cs | 1 + src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs | 12 ++++++++++++ src/core/Akka.Cluster.Tests/DowningProviderSpec.cs | 4 ++-- 6 files changed, 36 insertions(+), 3 deletions(-) diff --git a/docs/articles/clustering/split-brain-resolver.md b/docs/articles/clustering/split-brain-resolver.md index 7e98b7ce52a..5a8166297a6 100644 --- a/docs/articles/clustering/split-brain-resolver.md +++ b/docs/articles/clustering/split-brain-resolver.md @@ -41,6 +41,16 @@ Beginning in Akka.NET v1.4.16, the Akka.NET project has ported the original spli > [!IMPORTANT] > As of Akka.NET v1.5.2, the `keep-majority` split brain resolution strategy is now enabled by default. This should be acceptable for the majority of Akka.Cluster users, but please read on. +### Disabling the Default Downing Provider + +To disable the default Akka.Cluster downing provider, simply configure the following in your HOCON: + +```hocon +akka.cluster.downing-provider-class = "" +``` + +This will disable the split brain resolver / downing provider functionality altogether in Akka.NET. This was the default behavior for Akka.Cluster as of Akka.NET v1.5.1 and earlier. + ### Picking a Strategy In order to enable an Akka.NET split brain resolver in your cluster (they are not enabled by default), you will want to update your `akka.cluster` HOCON configuration to the following: diff --git a/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md b/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md index 5bb6ce5857d..f18728790c5 100644 --- a/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md +++ b/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md @@ -43,6 +43,16 @@ The `auto-down-unreachable-after` feature has been deprecated as of Akka.NET v1. The `keep-majority` split brain resolver will be used instead. See https://getakka.net/articles/cluster/split-brain-resolver.html for more details. ``` +#### Disabling the Default Downing Provider + +To disable the default Akka.Cluster downing provider, simply configure the following in your HOCON: + +```hocon +akka.cluster.downing-provider-class = "" +``` + +This will disable the split brain resolver / downing provider functionality altogether in Akka.NET. This was the default behavior for Akka.Cluster as of Akka.NET v1.5.1 and earlier. + ## Upgrading From Akka.NET v1.4 to v1.5 In case you need help upgrading: diff --git a/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonConfigSpec.cs b/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonConfigSpec.cs index 627e9e1a248..135eee78e27 100644 --- a/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonConfigSpec.cs +++ b/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonConfigSpec.cs @@ -37,7 +37,7 @@ public void ClusterSingletonManagerSettings_must_have_default_config() clusterSingletonManagerSettings.SingletonName.ShouldBe("singleton"); clusterSingletonManagerSettings.Role.ShouldBe(null); clusterSingletonManagerSettings.HandOverRetryInterval.TotalSeconds.ShouldBe(1); - clusterSingletonManagerSettings.RemovalMargin.TotalSeconds.ShouldBe(0); + clusterSingletonManagerSettings.RemovalMargin.TotalSeconds.ShouldBe(20); // now 20 due to default SBR settings var config = Sys.Settings.Config.GetConfig("akka.cluster.singleton"); Assert.False(config.IsNullOrEmpty()); diff --git a/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs b/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs index 744fbef779d..c7dc5e9ee5a 100644 --- a/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs +++ b/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs @@ -66,6 +66,7 @@ public static Config ClusterConfig() #akka.remote.log-remote-lifecycle-events = off akka.coordinated-shutdown.run-by-clr-shutdown-hook = off akka.coordinated-shutdown.terminate-actor-system = off + akka. #akka.loggers = [""Akka.TestKit.TestEventListener, Akka.TestKit""] akka.test { single-expect-default = 15 s diff --git a/src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs b/src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs index 6ca0c300a0f..0b009192030 100644 --- a/src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs +++ b/src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs @@ -91,5 +91,17 @@ public void Clustering_should_parse_nondefault_AppVersion() var settings = new ClusterSettings(config.WithFallback(Sys.Settings.Config), Sys.Name); settings.AppVersion.Should().Be(AppVersion.Zero); } + + /// + /// Validate that we can disable the default downing provider if needed + /// + [Fact] + public void Cluster_should_allow_disabling_of_default_DowningProvider() + { + // configure HOCON to disable the default akka.cluster downing provider + Config config = "akka.cluster.downing-provider-class = \"\""; + var settings = new ClusterSettings(config.WithFallback(Sys.Settings.Config), Sys.Name); + settings.DowningProviderType.Should().Be(); + } } } diff --git a/src/core/Akka.Cluster.Tests/DowningProviderSpec.cs b/src/core/Akka.Cluster.Tests/DowningProviderSpec.cs index 4cd0cbfc0c0..ac5ad50f635 100644 --- a/src/core/Akka.Cluster.Tests/DowningProviderSpec.cs +++ b/src/core/Akka.Cluster.Tests/DowningProviderSpec.cs @@ -34,7 +34,7 @@ public Props DowningActorProps } } - class DummyDowningProvider : IDowningProvider + internal class DummyDowningProvider : IDowningProvider { public readonly AtomicBoolean ActorPropsAccessed = new AtomicBoolean(false); public DummyDowningProvider(ActorSystem system, Cluster cluster) @@ -97,7 +97,7 @@ public void Downing_provider_should_use_specified_downing_provider() var downingProvider = Cluster.Get(system).DowningProvider; downingProvider.Should().BeOfType(); AwaitCondition(() => - (downingProvider as DummyDowningProvider).ActorPropsAccessed.Value, + ((DummyDowningProvider)downingProvider).ActorPropsAccessed.Value, TimeSpan.FromSeconds(3)); } } From 6e74d8832411db19f8204ca37fa1b1096f76ea5c Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Tue, 4 Apr 2023 14:47:11 -0500 Subject: [PATCH 05/16] added API approvals --- .../verify/CoreAPISpec.ApproveCluster.DotNet.verified.txt | 3 +++ .../verify/CoreAPISpec.ApproveCluster.Net.verified.txt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.DotNet.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.DotNet.verified.txt index 285f0c6b479..6ee9417d41a 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.DotNet.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.DotNet.verified.txt @@ -18,6 +18,7 @@ [assembly: System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName=".NET 6.0")] namespace Akka.Cluster { + [System.ObsoleteAttribute("No longer used as of Akka.NET v1.5.2")] public sealed class AutoDowning : Akka.Cluster.IDowningProvider { public AutoDowning(Akka.Actor.ActorSystem system, Akka.Cluster.Cluster cluster) { } @@ -192,6 +193,8 @@ namespace Akka.Cluster public ClusterSettings(Akka.Configuration.Config config, string systemName) { } public bool AllowWeaklyUpMembers { get; } public Akka.Util.AppVersion AppVersion { get; } + [System.ObsoleteAttribute("No longer used as of Akka.NET v1.5.2 - clustering defaults to using KeepMajority " + + "SBR instead")] public System.Nullable AutoDownUnreachableAfter { get; } public System.Type DowningProviderType { get; } public Akka.Configuration.Config FailureDetectorConfig { get; } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.Net.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.Net.verified.txt index 06124a13b85..94bec1b2ae3 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.Net.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.Net.verified.txt @@ -18,6 +18,7 @@ [assembly: System.Runtime.Versioning.TargetFrameworkAttribute(".NETStandard,Version=v2.0", FrameworkDisplayName=".NET Standard 2.0")] namespace Akka.Cluster { + [System.ObsoleteAttribute("No longer used as of Akka.NET v1.5.2")] public sealed class AutoDowning : Akka.Cluster.IDowningProvider { public AutoDowning(Akka.Actor.ActorSystem system, Akka.Cluster.Cluster cluster) { } @@ -192,6 +193,8 @@ namespace Akka.Cluster public ClusterSettings(Akka.Configuration.Config config, string systemName) { } public bool AllowWeaklyUpMembers { get; } public Akka.Util.AppVersion AppVersion { get; } + [System.ObsoleteAttribute("No longer used as of Akka.NET v1.5.2 - clustering defaults to using KeepMajority " + + "SBR instead")] public System.Nullable AutoDownUnreachableAfter { get; } public System.Type DowningProviderType { get; } public Akka.Configuration.Config FailureDetectorConfig { get; } From 97eb1c24d2bd5f8eb15973c470e320919758beeb Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Tue, 4 Apr 2023 14:56:20 -0500 Subject: [PATCH 06/16] disable SBR in MNTR --- src/core/Akka.Remote.TestKit/MultiNodeSpec.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/Akka.Remote.TestKit/MultiNodeSpec.cs b/src/core/Akka.Remote.TestKit/MultiNodeSpec.cs index 54083d14ae1..9373c86fa2b 100644 --- a/src/core/Akka.Remote.TestKit/MultiNodeSpec.cs +++ b/src/core/Akka.Remote.TestKit/MultiNodeSpec.cs @@ -379,6 +379,7 @@ public static Config BaseConfig } } } + cluster.downing-provider-class = """" #disable SBR by default }").WithFallback(TestKitBase.DefaultConfig); } } From 248404f0c4dcd55a00a6732a5535e847e7e0da4d Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Tue, 4 Apr 2023 14:59:37 -0500 Subject: [PATCH 07/16] Update MultiNodeClusterSpec.cs --- src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs b/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs index c7dc5e9ee5a..744fbef779d 100644 --- a/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs +++ b/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs @@ -66,7 +66,6 @@ public static Config ClusterConfig() #akka.remote.log-remote-lifecycle-events = off akka.coordinated-shutdown.run-by-clr-shutdown-hook = off akka.coordinated-shutdown.terminate-actor-system = off - akka. #akka.loggers = [""Akka.TestKit.TestEventListener, Akka.TestKit""] akka.test { single-expect-default = 15 s From 9df4d237ba28dd4705c44600c0b6da70ad5d3002 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Tue, 4 Apr 2023 19:20:36 -0500 Subject: [PATCH 08/16] fixed equality members on `InitJoin` --- src/core/Akka.Cluster/ClusterDaemon.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/core/Akka.Cluster/ClusterDaemon.cs b/src/core/Akka.Cluster/ClusterDaemon.cs index 89a8ef81f9a..c56d0d32db4 100644 --- a/src/core/Akka.Cluster/ClusterDaemon.cs +++ b/src/core/Akka.Cluster/ClusterDaemon.cs @@ -285,6 +285,21 @@ internal class JoinSeenNode /// internal class InitJoin : IClusterMessage, IDeadLetterSuppression { + /// + public override bool Equals(object obj) + { + return obj is InitJoin; + } + + protected bool Equals(InitJoin other) + { + return true; + } + + public override int GetHashCode() + { + return 1; + } } /// From ed9918cd5c1d7f75bc2ced0eeb3f646e50741f1a Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Tue, 4 Apr 2023 19:39:52 -0500 Subject: [PATCH 09/16] fix default auto-down-unreachable-after parse value --- src/core/Akka.Cluster/ClusterSettings.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/Akka.Cluster/ClusterSettings.cs b/src/core/Akka.Cluster/ClusterSettings.cs index 79e3b469fac..fbc4fcc0691 100644 --- a/src/core/Akka.Cluster/ClusterSettings.cs +++ b/src/core/Akka.Cluster/ClusterSettings.cs @@ -68,6 +68,8 @@ public ClusterSettings(Config config, string systemName) #pragma warning disable CS0618 AutoDownUnreachableAfter = clusterConfig.GetTimeSpanWithOffSwitch("auto-down-unreachable-after"); + if (AutoDownUnreachableAfter == default(TimeSpan)) // need to restore correct defaults now that it's been deleted from HOCON file + AutoDownUnreachableAfter = null; #pragma warning restore CS0618 Roles = clusterConfig.GetStringList("roles", new string[] { }).ToImmutableHashSet(); From b6a4ab5547ee385fe1597a385f49fe2f43d16c08 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Wed, 5 Apr 2023 08:55:53 -0500 Subject: [PATCH 10/16] disable SBR in all clustering specs --- src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs b/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs index 744fbef779d..0e511556736 100644 --- a/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs +++ b/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs @@ -59,6 +59,7 @@ public static Config ClusterConfig() retry-interval = 200ms waiting-for-state-timeout = 200ms } + downing-provider-class = """" # disable default SBR } akka.loglevel = INFO akka.log-dead-letters = off From 3df700b4b41210d449df13d4cc02c87b47af2090 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Wed, 5 Apr 2023 09:55:58 -0500 Subject: [PATCH 11/16] cleanup --- src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs | 2 ++ src/core/Akka.Cluster/ClusterDaemon.cs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs b/src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs index 0b009192030..d8f1dcb4f08 100644 --- a/src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs +++ b/src/core/Akka.Cluster.Tests/ClusterConfigSpec.cs @@ -45,7 +45,9 @@ public void Clustering_must_be_able_to_parse_generic_cluster_config_elements() settings.AllowWeaklyUpMembers.Should().BeTrue(); settings.WeaklyUpAfter.Should().Be(7.Seconds()); settings.PublishStatsInterval.Should().NotHaveValue(); +#pragma warning disable CS0618 settings.AutoDownUnreachableAfter.Should().NotHaveValue(); +#pragma warning restore CS0618 settings.DownRemovalMargin.Should().Be(TimeSpan.Zero); settings.MinNrOfMembers.Should().Be(1); settings.MinNrOfMembersOfRole.Should().Equal(ImmutableDictionary.Empty); diff --git a/src/core/Akka.Cluster/ClusterDaemon.cs b/src/core/Akka.Cluster/ClusterDaemon.cs index c56d0d32db4..f1ee16c0216 100644 --- a/src/core/Akka.Cluster/ClusterDaemon.cs +++ b/src/core/Akka.Cluster/ClusterDaemon.cs @@ -225,7 +225,7 @@ public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; - return obj is Welcome && Equals((Welcome)obj); + return obj is Welcome welcome && Equals(welcome); } private bool Equals(Welcome other) From 2563099107479b6d0fd5fdfdaefc92d1507e547e Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Wed, 5 Apr 2023 10:08:14 -0500 Subject: [PATCH 12/16] reconfigured SBR for Akka.Cluster.Sharding specs --- .../ClusterShardingSpec.cs | 3 ++- src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs | 2 +- src/core/Akka.Cluster/Configuration/Cluster.conf | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs index 3838d011d2e..dae4c7e1984 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs @@ -58,7 +58,8 @@ public ClusterShardingSpecConfig( CommonConfig = ConfigurationFactory.ParseString($@" akka.cluster.sharding.verbose-debug-logging = on #akka.loggers = [""akka.testkit.SilenceAllTestEventListener""] - + akka.cluster.downing-provider-class = ""Akka.Cluster.SBR.SplitBrainResolverProvider, Akka.Cluster"" + akka.cluster.split-brain-resolver.stable-after = 1s akka.cluster.roles = [""backend""] akka.cluster.distributed-data.gossip-interval = 1s akka.persistence.journal.sqlite-shared.timeout = 10s #the original default, base test uses 5s diff --git a/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs b/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs index 0e511556736..9cde3aced4e 100644 --- a/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs +++ b/src/core/Akka.Cluster.TestKit/MultiNodeClusterSpec.cs @@ -59,7 +59,7 @@ public static Config ClusterConfig() retry-interval = 200ms waiting-for-state-timeout = 200ms } - downing-provider-class = """" # disable default SBR + #downing-provider-class = """" # disable default SBR } akka.loglevel = INFO akka.log-dead-letters = off diff --git a/src/core/Akka.Cluster/Configuration/Cluster.conf b/src/core/Akka.Cluster/Configuration/Cluster.conf index 7d3df6e29bc..8ec86209fde 100644 --- a/src/core/Akka.Cluster/Configuration/Cluster.conf +++ b/src/core/Akka.Cluster/Configuration/Cluster.conf @@ -56,8 +56,6 @@ akka { # - argument 1: accepting an `ActorSystem` # - argument 2: accepting an `Akka.Cluster.Cluster` downing-provider-class = "Akka.Cluster.SBR.SplitBrainResolverProvider, Akka.Cluster" - - # If this is set to "off", the leader will not move 'Joining' members to 'Up' during a network # split. This feature allows the leader to accept 'Joining' members to be 'WeaklyUp' From 5ab3acc0f351b1f753a7a0a54c3da12e84bd7f71 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Wed, 5 Apr 2023 10:10:28 -0500 Subject: [PATCH 13/16] fixed - had to adjust down-removal-margin --- .../Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs index dae4c7e1984..987b1c26352 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs @@ -60,6 +60,7 @@ public ClusterShardingSpecConfig( #akka.loggers = [""akka.testkit.SilenceAllTestEventListener""] akka.cluster.downing-provider-class = ""Akka.Cluster.SBR.SplitBrainResolverProvider, Akka.Cluster"" akka.cluster.split-brain-resolver.stable-after = 1s + akka.cluster.down-removal-margin = 1s akka.cluster.roles = [""backend""] akka.cluster.distributed-data.gossip-interval = 1s akka.persistence.journal.sqlite-shared.timeout = 10s #the original default, base test uses 5s From 6ee93e55b7c1b0bff5db5bb56523cb74965d0323 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Wed, 5 Apr 2023 11:36:17 -0500 Subject: [PATCH 14/16] fixed SBR issues with Akka.Cluster.Sharding MNTR --- .../MultiNodeClusterShardingConfig.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/MultiNodeClusterShardingConfig.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/MultiNodeClusterShardingConfig.cs index 31ccb22e11e..8ba93af5664 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/MultiNodeClusterShardingConfig.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/MultiNodeClusterShardingConfig.cs @@ -58,7 +58,9 @@ protected MultiNodeClusterShardingConfig( Common = ConfigurationFactory.ParseString($@" akka.actor.provider = ""cluster"" - akka.cluster.auto-down-unreachable-after = 0s + akka.cluster.downing-provider-class = ""Akka.Cluster.SBR.SplitBrainResolverProvider, Akka.Cluster"" + akka.cluster.split-brain-resolver.stable-after = 1s + akka.cluster.down-removal-margin = 1s akka.cluster.sharding.state-store-mode = ""{mode}"" akka.cluster.sharding.remember-entities = {rememberEntities.ToString().ToLowerInvariant()} akka.cluster.sharding.remember-entities-store = ""{rememberEntitiesStore}"" From 251fadebbb57ae61ae947c3bdaebd4545d99519b Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Wed, 5 Apr 2023 12:51:06 -0500 Subject: [PATCH 15/16] restored `auto-down-unreachable-after` Can't really run the Akka.Cluster.Sharding MNTR suite without it --- .../whats-new/akkadotnet-v1.5-upgrade-advisories.md | 2 +- .../ClusterShardingSpec.cs | 4 +--- .../MultiNodeClusterShardingConfig.cs | 4 +--- src/core/Akka.Cluster.Tests/DowningProviderSpec.cs | 6 ++++-- src/core/Akka.Cluster/AutoDown.cs | 3 ++- src/core/Akka.Cluster/ClusterSettings.cs | 13 +++++++++---- src/core/Akka.Cluster/Configuration/Cluster.conf | 8 ++++++++ 7 files changed, 26 insertions(+), 14 deletions(-) diff --git a/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md b/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md index f18728790c5..886e5d23e4e 100644 --- a/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md +++ b/docs/community/whats-new/akkadotnet-v1.5-upgrade-advisories.md @@ -36,7 +36,7 @@ If you were already running with a custom SBR enabled, this change won't affect If you weren't running with an SBR enabled, you should read the [Akka.Cluster Split Brain Resolver documentation](xref:split-brain-resolver). -Also worth noting: we've disabled the `akka.cluster.auto-down-unreachable-after` setting as it's always been a poor and shoddy way to manage network partitions inside Akka.Cluster. If you have that setting enabled it will be ignored and you'll see the following warning appear instead: +Also worth noting: we've deprecated the `akka.cluster.auto-down-unreachable-after` setting as it's always been a poor and shoddy way to manage network partitions inside Akka.Cluster. If you have that setting enabled you'll see the following warning appear: ```shell The `auto-down-unreachable-after` feature has been deprecated as of Akka.NET v1.5.2 and will be removed in a future version of Akka.NET. diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs index 987b1c26352..d04710033db 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/ClusterShardingSpec.cs @@ -58,9 +58,7 @@ public ClusterShardingSpecConfig( CommonConfig = ConfigurationFactory.ParseString($@" akka.cluster.sharding.verbose-debug-logging = on #akka.loggers = [""akka.testkit.SilenceAllTestEventListener""] - akka.cluster.downing-provider-class = ""Akka.Cluster.SBR.SplitBrainResolverProvider, Akka.Cluster"" - akka.cluster.split-brain-resolver.stable-after = 1s - akka.cluster.down-removal-margin = 1s + akka.cluster.auto-down-unreachable-after = 0s akka.cluster.roles = [""backend""] akka.cluster.distributed-data.gossip-interval = 1s akka.persistence.journal.sqlite-shared.timeout = 10s #the original default, base test uses 5s diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/MultiNodeClusterShardingConfig.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/MultiNodeClusterShardingConfig.cs index 8ba93af5664..31ccb22e11e 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/MultiNodeClusterShardingConfig.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/MultiNodeClusterShardingConfig.cs @@ -58,9 +58,7 @@ protected MultiNodeClusterShardingConfig( Common = ConfigurationFactory.ParseString($@" akka.actor.provider = ""cluster"" - akka.cluster.downing-provider-class = ""Akka.Cluster.SBR.SplitBrainResolverProvider, Akka.Cluster"" - akka.cluster.split-brain-resolver.stable-after = 1s - akka.cluster.down-removal-margin = 1s + akka.cluster.auto-down-unreachable-after = 0s akka.cluster.sharding.state-store-mode = ""{mode}"" akka.cluster.sharding.remember-entities = {rememberEntities.ToString().ToLowerInvariant()} akka.cluster.sharding.remember-entities-store = ""{rememberEntitiesStore}"" diff --git a/src/core/Akka.Cluster.Tests/DowningProviderSpec.cs b/src/core/Akka.Cluster.Tests/DowningProviderSpec.cs index ac5ad50f635..dd27fbc859c 100644 --- a/src/core/Akka.Cluster.Tests/DowningProviderSpec.cs +++ b/src/core/Akka.Cluster.Tests/DowningProviderSpec.cs @@ -80,10 +80,12 @@ public void Downing_provider_should_default_to_KeepMajority() [Fact] public void Downing_provider_should_ignore_AutoDowning_if_auto_down_unreachable_after_is_configured() { - var config = ConfigurationFactory.ParseString(@"akka.cluster.auto-down-unreachable-after=18s"); + var config = ConfigurationFactory.ParseString(@" + akka.cluster.downing-provider-class = """" + akka.cluster.auto-down-unreachable-after=18s"); using (var system = ActorSystem.Create("auto-downing", config.WithFallback(BaseConfig))) { - Cluster.Get(system).DowningProvider.Should().BeOfType(); + Cluster.Get(system).DowningProvider.Should().BeOfType(); } } diff --git a/src/core/Akka.Cluster/AutoDown.cs b/src/core/Akka.Cluster/AutoDown.cs index a1e5ceb476d..516efc2a328 100644 --- a/src/core/Akka.Cluster/AutoDown.cs +++ b/src/core/Akka.Cluster/AutoDown.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Immutable; using Akka.Actor; +using Akka.Annotations; using Akka.Event; using Akka.Configuration; using static Akka.Cluster.MembershipState; @@ -270,7 +271,7 @@ private void Remove(UniqueAddress node) /// /// Used when no custom provider is configured and 'auto-down-unreachable-after' is enabled. /// - [Obsolete("No longer used as of Akka.NET v1.5.2")] + [InternalApi] // really only used during MNTR for Akka.Cluster.Sharding public sealed class AutoDowning : IDowningProvider { private readonly ActorSystem _system; diff --git a/src/core/Akka.Cluster/ClusterSettings.cs b/src/core/Akka.Cluster/ClusterSettings.cs index fbc4fcc0691..d12f23f5345 100644 --- a/src/core/Akka.Cluster/ClusterSettings.cs +++ b/src/core/Akka.Cluster/ClusterSettings.cs @@ -68,8 +68,6 @@ public ClusterSettings(Config config, string systemName) #pragma warning disable CS0618 AutoDownUnreachableAfter = clusterConfig.GetTimeSpanWithOffSwitch("auto-down-unreachable-after"); - if (AutoDownUnreachableAfter == default(TimeSpan)) // need to restore correct defaults now that it's been deleted from HOCON file - AutoDownUnreachableAfter = null; #pragma warning restore CS0618 Roles = clusterConfig.GetStringList("roles", new string[] { }).ToImmutableHashSet(); @@ -91,7 +89,14 @@ public ClusterSettings(Config config, string systemName) VerboseGossipReceivedLogging = clusterConfig.GetBoolean("debug.verbose-receive-gossip-logging", false); var downingProviderClassName = clusterConfig.GetString("downing-provider-class", null); - DowningProviderType = !string.IsNullOrEmpty(downingProviderClassName) ? Type.GetType(downingProviderClassName, true) : typeof(NoDowning); + if (!string.IsNullOrEmpty(downingProviderClassName)) + DowningProviderType = Type.GetType(downingProviderClassName, true); +#pragma warning disable CS0618 + else if (AutoDownUnreachableAfter.HasValue) +#pragma warning restore CS0618 + DowningProviderType = typeof(AutoDowning); + else + DowningProviderType = typeof(NoDowning); RunCoordinatedShutdownWhenDown = clusterConfig.GetBoolean("run-coordinated-shutdown-when-down", false); @@ -207,7 +212,7 @@ TimeSpan GetWeaklyUpDuration() /// /// Obsolete. No longer used as of Akka.NET v1.5. /// - [Obsolete(message:"No longer used as of Akka.NET v1.5.2 - clustering defaults to using KeepMajority SBR instead")] + [Obsolete(message:"Deprecated as of Akka.NET v1.5.2 - clustering defaults to using KeepMajority SBR instead")] public TimeSpan? AutoDownUnreachableAfter { get; } /// diff --git a/src/core/Akka.Cluster/Configuration/Cluster.conf b/src/core/Akka.Cluster/Configuration/Cluster.conf index 8ec86209fde..b9644c6d4f5 100644 --- a/src/core/Akka.Cluster/Configuration/Cluster.conf +++ b/src/core/Akka.Cluster/Configuration/Cluster.conf @@ -25,6 +25,14 @@ akka { # If a join request fails it will be retried after this period. # Disable join retry by specifying "off". retry-unsuccessful-join-after = 10s + + # Should the 'leader' in the cluster be allowed to automatically mark + # unreachable nodes as DOWN after a configured time of unreachability? + # Using auto-down implies that two separate clusters will automatically be + # formed in case of network partition. + # Disable with "off" or specify a duration to enable auto-down. + # If a downing-provider-class is configured this setting is ignored. + auto-down-unreachable-after = off # The joining of given seed nodes will by default be retried indefinitely until # a successful join. That process can be aborted if unsuccessful by defining this From 7eedcdde2f187274d066161e6ef10a012261d5b4 Mon Sep 17 00:00:00 2001 From: Aaron Stannard Date: Wed, 5 Apr 2023 13:04:41 -0500 Subject: [PATCH 16/16] approave API changes --- .../verify/CoreAPISpec.ApproveCluster.DotNet.verified.txt | 6 +++--- .../verify/CoreAPISpec.ApproveCluster.Net.verified.txt | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.DotNet.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.DotNet.verified.txt index 6ee9417d41a..5ba6c794e8f 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.DotNet.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.DotNet.verified.txt @@ -18,7 +18,7 @@ [assembly: System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName=".NET 6.0")] namespace Akka.Cluster { - [System.ObsoleteAttribute("No longer used as of Akka.NET v1.5.2")] + [Akka.Annotations.InternalApiAttribute()] public sealed class AutoDowning : Akka.Cluster.IDowningProvider { public AutoDowning(Akka.Actor.ActorSystem system, Akka.Cluster.Cluster cluster) { } @@ -193,8 +193,8 @@ namespace Akka.Cluster public ClusterSettings(Akka.Configuration.Config config, string systemName) { } public bool AllowWeaklyUpMembers { get; } public Akka.Util.AppVersion AppVersion { get; } - [System.ObsoleteAttribute("No longer used as of Akka.NET v1.5.2 - clustering defaults to using KeepMajority " + - "SBR instead")] + [System.ObsoleteAttribute("Deprecated as of Akka.NET v1.5.2 - clustering defaults to using KeepMajority SBR " + + "instead")] public System.Nullable AutoDownUnreachableAfter { get; } public System.Type DowningProviderType { get; } public Akka.Configuration.Config FailureDetectorConfig { get; } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.Net.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.Net.verified.txt index 94bec1b2ae3..60b87ce8f06 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.Net.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCluster.Net.verified.txt @@ -18,7 +18,7 @@ [assembly: System.Runtime.Versioning.TargetFrameworkAttribute(".NETStandard,Version=v2.0", FrameworkDisplayName=".NET Standard 2.0")] namespace Akka.Cluster { - [System.ObsoleteAttribute("No longer used as of Akka.NET v1.5.2")] + [Akka.Annotations.InternalApiAttribute()] public sealed class AutoDowning : Akka.Cluster.IDowningProvider { public AutoDowning(Akka.Actor.ActorSystem system, Akka.Cluster.Cluster cluster) { } @@ -193,8 +193,8 @@ namespace Akka.Cluster public ClusterSettings(Akka.Configuration.Config config, string systemName) { } public bool AllowWeaklyUpMembers { get; } public Akka.Util.AppVersion AppVersion { get; } - [System.ObsoleteAttribute("No longer used as of Akka.NET v1.5.2 - clustering defaults to using KeepMajority " + - "SBR instead")] + [System.ObsoleteAttribute("Deprecated as of Akka.NET v1.5.2 - clustering defaults to using KeepMajority SBR " + + "instead")] public System.Nullable AutoDownUnreachableAfter { get; } public System.Type DowningProviderType { get; } public Akka.Configuration.Config FailureDetectorConfig { get; }