diff --git a/src/contrib/cluster/Akka.Cluster.Tools/Singleton/ClusterSingletonManager.cs b/src/contrib/cluster/Akka.Cluster.Tools/Singleton/ClusterSingletonManager.cs index 197f5cc429e..fb23c584376 100644 --- a/src/contrib/cluster/Akka.Cluster.Tools/Singleton/ClusterSingletonManager.cs +++ b/src/contrib/cluster/Akka.Cluster.Tools/Singleton/ClusterSingletonManager.cs @@ -34,9 +34,6 @@ public interface IClusterSingletonMessage { } [Serializable] internal sealed class HandOverToMe : IClusterSingletonMessage, IDeadLetterSuppression { - /// - /// TBD - /// public static HandOverToMe Instance { get; } = new(); private HandOverToMe() { } } @@ -49,9 +46,6 @@ private HandOverToMe() { } [Serializable] internal sealed class HandOverInProgress : IClusterSingletonMessage { - /// - /// TBD - /// public static HandOverInProgress Instance { get; } = new(); private HandOverInProgress() { } } @@ -64,9 +58,6 @@ private HandOverInProgress() { } [Serializable] internal sealed class HandOverDone : IClusterSingletonMessage { - /// - /// TBD - /// public static HandOverDone Instance { get; } = new(); private HandOverDone() { } } @@ -113,72 +104,47 @@ private StartOldestChangedBuffer() { } internal sealed record HandOverRetry(int Count); /// - /// TBD + /// Used to retry a failed takeover operation. /// + /// The number of retries [Serializable] - internal sealed class TakeOverRetry - { - /// - /// TBD - /// - public int Count { get; } + internal sealed record TakeOverRetry(int Count); - /// - /// TBD - /// - /// TBD - public TakeOverRetry(int count) - { - Count = count; - } - } - /// - /// TBD - /// [Serializable] internal sealed class LeaseRetry: INoSerializationVerificationNeeded { - /// - /// TBD - /// public static LeaseRetry Instance { get; } = new(); private LeaseRetry() { } } /// - /// TBD + /// The data type used by the /// public interface IClusterSingletonData { } /// - /// TBD + /// The initial state of the cluster singleton manager at startup before it receives any data. /// [Serializable] internal sealed class Uninitialized : IClusterSingletonData { - /// - /// TBD - /// public static Uninitialized Instance { get; } = new(); private Uninitialized() { } } /// - /// TBD + /// The state used after we've initialized and are aware of all of the other + /// older members currently present in the cluster. /// [Serializable] internal sealed class YoungerData : IClusterSingletonData { /// - /// TBD + /// The age-ordered (ascending) set of addresses of older nodes than us in the cluster. /// public ImmutableList Oldest { get; } - - /// - /// TBD - /// - /// TBD + public YoungerData(ImmutableList oldest) { Oldest = oldest; @@ -449,19 +415,19 @@ public enum ClusterSingletonState /// WasOldest, /// - /// We are c + /// We are handing over our singleton to the new oldest node. /// HandingOver, /// - /// TBD + /// Not used /// TakeOver, /// - /// TBD + /// We are shutting down. /// Stopping, /// - /// TBD + /// We have shut down and are terminating. /// End } @@ -537,7 +503,7 @@ public static Config DefaultConfig() /// /// of the singleton actor instance. /// Cluster singleton manager settings. - /// TBD + /// Props for the . public static Props Props(Props singletonProps, ClusterSingletonManagerSettings settings) { return Props(singletonProps, PoisonPill.Instance, settings); @@ -554,7 +520,7 @@ public static Props Props(Props singletonProps, ClusterSingletonManagerSettings /// perfectly fine if you only need to stop the actor. /// /// Cluster singleton manager settings. - /// TBD + /// Props for the . public static Props Props(Props singletonProps, object terminationMessage, ClusterSingletonManagerSettings settings) { return Actor.Props.Create(() => new ClusterSingletonManager(singletonProps, terminationMessage, settings)) @@ -576,7 +542,7 @@ public static Props Props(Props singletonProps, object terminationMessage, Clust private bool _selfExited; // started when self member is Up - private IActorRef _oldestChangedBuffer; + private IActorRef? _oldestChangedBuffer; // keep track of previously removed members private ImmutableDictionary _removed = ImmutableDictionary.Empty; private readonly TimeSpan _removalMargin; @@ -584,7 +550,6 @@ public static Props Props(Props singletonProps, object terminationMessage, Clust private readonly int _maxTakeOverRetries; private readonly Cluster _cluster = Cluster.Get(Context.System); private readonly UniqueAddress _selfUniqueAddress; - private ILoggingAdapter _log; private readonly CoordinatedShutdown _coordShutdown = CoordinatedShutdown.Get(Context.System); private readonly TaskCompletionSource _memberExitingProgress = new(); @@ -592,16 +557,7 @@ public static Props Props(Props singletonProps, object terminationMessage, Clust private readonly string _singletonLeaseName; private readonly Lease? _lease; private readonly TimeSpan _leaseRetryInterval = TimeSpan.FromSeconds(5); // won't be used - - /// - /// TBD - /// - /// TBD - /// TBD - /// TBD - /// TBD - /// TBD - /// TBD + public ClusterSingletonManager(Props singletonProps, object terminationMessage, ClusterSingletonManagerSettings settings) { var role = settings.Role; @@ -619,6 +575,17 @@ public ClusterSingletonManager(Props singletonProps, object terminationMessage, .GetLease(_singletonLeaseName, settings.LeaseSettings.LeaseImplementation, _cluster.SelfAddress.HostPort()); _leaseRetryInterval = settings.LeaseSettings.LeaseRetryInterval; } + + // Added in v1.5.27 to signal to users who were considering AppVersion + // in their singleton placement decisions that we don't do that any more +#pragma warning disable CS0618 // Type or member is obsolete + if (settings.ConsiderAppVersion) +#pragma warning restore CS0618 // Type or member is obsolete + { + Log.Warning("As of Akka.NET v1.5.27, The 'ConsiderAppVersion' setting is no longer supported and will " + + "be removed in a future version because this setting is inherently unsafe and can result in split brains. " + + "Singleton instances will always be created on the oldest member."); + } _removalMargin = (settings.RemovalMargin <= TimeSpan.Zero) ? _cluster.DowningProvider.DownRemovalMargin : settings.RemovalMargin; @@ -661,7 +628,7 @@ private void SetupCoordinatedShutdown() }); } - private ILoggingAdapter Log { get { return _log ??= Context.GetLogger(); } } + private ILoggingAdapter Log { get; } = Context.GetLogger(); /// protected override void PreStart() diff --git a/src/contrib/cluster/Akka.Cluster.Tools/Singleton/ClusterSingletonManagerSettings.cs b/src/contrib/cluster/Akka.Cluster.Tools/Singleton/ClusterSingletonManagerSettings.cs index 0345b43a104..c7ae188be51 100644 --- a/src/contrib/cluster/Akka.Cluster.Tools/Singleton/ClusterSingletonManagerSettings.cs +++ b/src/contrib/cluster/Akka.Cluster.Tools/Singleton/ClusterSingletonManagerSettings.cs @@ -99,6 +99,7 @@ private static string RoleOption(string role) /// When set to false, singleton instance will always be created on oldest member. /// When set to true, singleton instance will be created on the oldest member with the highest number. /// + [Obsolete("ConsiderAppVersion is not used anymore and will be removed in future versions.")] public bool ConsiderAppVersion { get; } /// @@ -188,7 +189,9 @@ public ClusterSingletonManagerSettings( RemovalMargin = removalMargin; HandOverRetryInterval = handOverRetryInterval; LeaseSettings = leaseSettings; +#pragma warning disable CS0618 // Type or member is obsolete ConsiderAppVersion = considerAppVersion; +#pragma warning restore CS0618 // Type or member is obsolete } /// diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveClusterTools.DotNet.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveClusterTools.DotNet.verified.txt index 5b219595503..bae1c134565 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveClusterTools.DotNet.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveClusterTools.DotNet.verified.txt @@ -417,6 +417,7 @@ namespace Akka.Cluster.Tools.Singleton { public ClusterSingletonManagerSettings(string singletonName, string role, System.TimeSpan removalMargin, System.TimeSpan handOverRetryInterval, bool considerAppVersion) { } public ClusterSingletonManagerSettings(string singletonName, string role, System.TimeSpan removalMargin, System.TimeSpan handOverRetryInterval, Akka.Coordination.LeaseUsageSettings leaseSettings, bool considerAppVersion) { } + [System.ObsoleteAttribute("ConsiderAppVersion is not used anymore and will be removed in future versions.")] public bool ConsiderAppVersion { get; } public System.TimeSpan HandOverRetryInterval { get; } public Akka.Coordination.LeaseUsageSettings LeaseSettings { get; } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveClusterTools.Net.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveClusterTools.Net.verified.txt index 8c151712151..7d54ed7767b 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveClusterTools.Net.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveClusterTools.Net.verified.txt @@ -417,6 +417,7 @@ namespace Akka.Cluster.Tools.Singleton { public ClusterSingletonManagerSettings(string singletonName, string role, System.TimeSpan removalMargin, System.TimeSpan handOverRetryInterval, bool considerAppVersion) { } public ClusterSingletonManagerSettings(string singletonName, string role, System.TimeSpan removalMargin, System.TimeSpan handOverRetryInterval, Akka.Coordination.LeaseUsageSettings leaseSettings, bool considerAppVersion) { } + [System.ObsoleteAttribute("ConsiderAppVersion is not used anymore and will be removed in future versions.")] public bool ConsiderAppVersion { get; } public System.TimeSpan HandOverRetryInterval { get; } public Akka.Coordination.LeaseUsageSettings LeaseSettings { get; }