diff --git a/BREAKING_CHANGES_V1.6.md b/BREAKING_CHANGES_V1.6.md index 9b0321946c2..eb1ea922138 100644 --- a/BREAKING_CHANGES_V1.6.md +++ b/BREAKING_CHANGES_V1.6.md @@ -40,6 +40,7 @@ of `Behavior`, `Wire`, `API` (combine with `+`). | Status | PR / Branch | Component | Type | Change | Migration | |--------|-------------|-----------|------|--------|-----------| +| Planned | `feature/default-bounded-shard-rebalancing` | `Akka.Cluster.Sharding` | Behavior | The default `rebalance-absolute-limit` is now `20`, selecting the bounded shard allocation strategy instead of the legacy threshold-based strategy. | To retain the legacy strategy temporarily, explicitly set `akka.cluster.sharding.least-shard-allocation-strategy.rebalance-absolute-limit = 0`. Review `rebalance-threshold` and `max-simultaneous-rebalance`, which do not apply while the bounded strategy is active. | | Planned | `fix/artery-daemonmsgcreate-control-stream` | `Akka.Remote` (Artery) | Behavior | Remote deployment's `DaemonMsgCreate` now travels over Artery's CONTROL stream (as a plain envelope, no delivery/ack sequencing) instead of the ordinary stream, ordering it ahead of the `Watch` that remote deployment sends immediately afterwards. Previously the two rode independent, unordered TCP connections and `Watch` systematically arrived first, so the receiver replied `DeathWatchNotification(existenceConfirmed: false)` for a not-yet-created actor and the deployer reaped the freshly-deployed routee before its `Supervise` registration landed, emptying cluster router pools. Additionally (Pekko parity), inbound ordinary messages addressed to a remote-deployed recipient that has not been created yet are no longer dead-lettered immediately: the resolve is retried on a bounded schedule (20 attempts x 50ms, buffered per recipient in FIFO order) so first messages that arrive ahead of the in-flight `DaemonMsgCreate` are delivered once the actor exists; paths that never resolve are banned and dead-letter as before. | No action required -- this is a bug fix restoring correct create-before-watch ordering; code that (incorrectly) depended on the old race is unsupported. | | Planned | `feature/artery-test-mode` | `Akka.Remote` | Behavior | System UID generation (`AddressUidExtension` / `AddressUid`) now uses a cryptographic RNG instead of the `Environment.TickCount`-seeded `ThreadLocalRandom`. Previously, multiple processes started within the same millisecond tick (e.g. every node of a multi-node test spawning at once) could draw IDENTICAL system UIDs, silently corrupting Artery's uid-keyed identity (handshakes, quarantine, association reverse index). UIDs remain nonzero and in the legacy `[1, int.MaxValue]` range at the default (`use-64bit-system-uids = off`). | Nothing required -- UIDs were always documented as random; only code depending on the (buggy) time-seeded determinism could observe a difference. | | Planned | `feature/artery-test-mode` | `Akka.Remote` (Artery) / `Akka.Remote.TestKit` | Behavior | New `akka.remote.artery.advanced.test-mode` setting (default `off`, Pekko key parity) enables failure-injection test stages in Artery's stream pipelines, and `ArteryRemoting.ManagementCommand` now honors `SetThrottle` with `Blackhole`/`Unthrottled` (returning `true`; previously always `false`) so TestConductor `Blackhole`/`PassThrough` work over Artery. Rate throttles (`TokenBucket`) and `ForceDisassociate` remain unsupported on Artery (still `false`, matching Pekko). `MultiNodeConfig.TestTransport = true` now also sets Artery test-mode on, and the TestKit `Player` now treats a `false` `ManagementCommand` result as a failure (previously reported success for a silently ignored command). | Nothing at the default (`test-mode = off` composes byte-identical pipelines). Test code that relied on `ManagementCommand` always returning `false` on Artery, or on the Player treating `false` as success, must account for the new semantics. | diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/ClusterShardingConfigSpec.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/ClusterShardingConfigSpec.cs index e257685b1c5..8e18c8531ee 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/ClusterShardingConfigSpec.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/ClusterShardingConfigSpec.cs @@ -28,7 +28,7 @@ public static Config GetConfig() [Fact] public void Should_cluster_sharding_settings_have_default_config() { - ClusterSharding.Get(Sys); + var clusterSharding = ClusterSharding.Get(Sys); var config = Sys.Settings.Config.GetConfig("akka.cluster.sharding"); var clusterShardingSettings = ClusterShardingSettings.Create(Sys); @@ -55,6 +55,10 @@ public void Should_cluster_sharding_settings_have_default_config() Assert.Equal(1, config.GetInt("least-shard-allocation-strategy.rebalance-threshold")); Assert.Equal(3, config.GetInt("least-shard-allocation-strategy.max-simultaneous-rebalance")); + Assert.Equal(20, config.GetInt("least-shard-allocation-strategy.rebalance-absolute-limit")); + Assert.Equal(0.1, config.GetDouble("least-shard-allocation-strategy.rebalance-relative-limit")); + clusterSharding.DefaultShardAllocationStrategy(clusterShardingSettings) + .Should().BeOfType(); Assert.Equal("all", config.GetString("entity-recovery-strategy")); Assert.Equal(TimeSpan.FromMilliseconds(100), config.GetTimeSpan("entity-recovery-constant-rate-strategy.frequency")); diff --git a/src/contrib/cluster/Akka.Cluster.Sharding/ClusterSharding.cs b/src/contrib/cluster/Akka.Cluster.Sharding/ClusterSharding.cs index 9639469e183..1f14a7f1444 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding/ClusterSharding.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding/ClusterSharding.cs @@ -1475,8 +1475,7 @@ public IShardAllocationStrategy DefaultShardAllocationStrategy(ClusterShardingSe } else { - // TODO: remove this in v1.6 and force all users to use only the new strategy going forward - // old algorithm + // Explicit compatibility mode for deployments that still use the legacy strategy. var threshold = settings.TuningParameters.LeastShardAllocationRebalanceThreshold; var maxSimultaneousRebalance = settings.TuningParameters.LeastShardAllocationMaxSimultaneousRebalance; #pragma warning disable CS0618 // Type or member is obsolete diff --git a/src/contrib/cluster/Akka.Cluster.Sharding/reference.conf b/src/contrib/cluster/Akka.Cluster.Sharding/reference.conf index 952514e12bb..2e61b444deb 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding/reference.conf +++ b/src/contrib/cluster/Akka.Cluster.Sharding/reference.conf @@ -100,17 +100,14 @@ akka.cluster.sharding { # Settings for LeastShardAllocationStrategy. # - # A new rebalance algorithm was included in Akka.Net 1.4.11. It can reach optimal balance in - # less rebalance rounds (typically 1 or 2 rounds). The amount of shards to rebalance in each - # round can still be limited to make it progress slower. For backwards compatibility - # the new algorithm is not enabled by default. Enable the new algorithm by setting - # `rebalance-absolute-limit` > 0, for example: - # akka.cluster.sharding.least-shard-allocation-strategy.rebalance-absolute-limit=20 - # The new algorithm is recommended and will become the default in future versions of Akka. + # The bounded rebalance algorithm can reach optimal balance in fewer rebalance rounds than the + # legacy threshold-based algorithm. The absolute and relative limits bound the number of shards + # moved in each round. Set `rebalance-absolute-limit = 0` only to retain legacy behavior during + # migration. least-shard-allocation-strategy { # Maximum number of shards that will be rebalanced in one rebalance round. # The lower of this and `rebalance-relative-limit` will be used. - rebalance-absolute-limit = 0 + rebalance-absolute-limit = 20 # Maximum number of shards that will be rebalanced in one rebalance round. # Fraction of total number of (known) shards.