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; }