From 762df163b1688ce715ab5e8ddd8038a01f6326ad Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Fri, 26 Jul 2024 23:58:50 +0700 Subject: [PATCH 1/7] Fix how ClusterShardingSettings were applied --- .../AkkaClusterHostingExtensions.cs | 41 +++++++++++-------- 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs b/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs index 76f7499..d382841 100644 --- a/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs +++ b/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs @@ -302,13 +302,13 @@ public sealed class ShardOptions /// or is set to false. /// public TimeSpan? PassivateIdleEntityAfter { get; set; } - - internal void Apply(AkkaConfigurationBuilder builder) + + public Config ToConfig() => ToString(); + + public override string ToString() { - DistributedData.Apply(builder); - var sb = new StringBuilder(); - + if (Role is not null) sb.AppendLine($"role = {Role.ToHocon()}"); @@ -344,12 +344,7 @@ internal void Apply(AkkaConfigurationBuilder builder) else if(PassivateIdleEntityAfter is not null) sb.AppendLine($"passivate-idle-entity-after = {PassivateIdleEntityAfter.ToHocon()}"); - if (sb.Length > 0) - { - sb.Insert(0, "akka.cluster.sharding {\n"); - sb.AppendLine("}"); - builder.AddHocon(sb.ToString(), HoconAddMode.Prepend); - } + return sb.ToString(); } } @@ -850,7 +845,7 @@ public static AkkaConfigurationBuilder WithShardRegion( IMessageExtractor messageExtractor, ShardOptions shardOptions) { - shardOptions.Apply(builder); + shardOptions.DistributedData.Apply(builder); builder.AddHocon( ClusterSharding.DefaultConfig().WithFallback(DistributedData.DistributedData.DefaultConfig()), HoconAddMode.Append); @@ -860,7 +855,12 @@ public static AkkaConfigurationBuilder WithShardRegion( async Task Resolver(ActorSystem system, IActorRegistry registry, IDependencyResolver resolver) { var props = entityPropsFactory(system, registry, resolver); - var settings = ClusterShardingSettings.Create(system); + var shardingConfig = shardOptions.ToConfig() + .WithFallback(system.Settings.Config.GetConfig("akka.cluster.sharding")); + var coordinatorConfig = system.Settings.Config.GetConfig( + shardingConfig.GetString("coordinator-singleton")); + + var settings = ClusterShardingSettings.Create(shardingConfig, coordinatorConfig); var allocationStrategy = ClusterSharding.Get(system).DefaultShardAllocationStrategy(settings); var shardRegion = await ClusterSharding.Get(system).StartAsync( typeName, props, settings, messageExtractor, allocationStrategy, @@ -911,23 +911,28 @@ public static AkkaConfigurationBuilder WithShardRegion( ExtractShardId extractShardId, ShardOptions shardOptions) { - shardOptions.Apply(builder); + shardOptions.DistributedData.Apply(builder); builder.AddHocon( ClusterSharding.DefaultConfig().WithFallback(DistributedData.DistributedData.DefaultConfig()), HoconAddMode.Append); - + + return builder.StartActors(Resolver); + async Task Resolver(ActorSystem system, IActorRegistry registry, IDependencyResolver resolver) { var props = entityPropsFactory(system, registry, resolver); - var settings = ClusterShardingSettings.Create(system); + var shardingConfig = shardOptions.ToConfig() + .WithFallback(system.Settings.Config.GetConfig("akka.cluster.sharding")); + var coordinatorConfig = system.Settings.Config.GetConfig( + shardingConfig.GetString("coordinator-singleton")); + + var settings = ClusterShardingSettings.Create(shardingConfig, coordinatorConfig); var allocationStrategy = ClusterSharding.Get(system).DefaultShardAllocationStrategy(settings); var shardRegion = await ClusterSharding.Get(system).StartAsync( typeName, props, settings, extractEntityId, extractShardId, allocationStrategy, shardOptions.HandOffStopMessage ?? PoisonPill.Instance).ConfigureAwait(false); registry.Register(shardRegion); } - - return builder.StartActors(Resolver); } /// From 97ce1a357439abc0403846bc749229ba0d62e1f4 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Sat, 27 Jul 2024 00:15:08 +0700 Subject: [PATCH 2/7] Add default cluster sharding API --- .../AkkaClusterHostingExtensions.cs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs b/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs index d382841..8ef1e38 100644 --- a/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs +++ b/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs @@ -641,6 +641,35 @@ public static AkkaConfigurationBuilder WithDistributedData( builder.AddHocon(DistributedData.DistributedData.DefaultConfig(), HoconAddMode.Append); return builder; } + + /// + /// Applies a default setting that, if not overriden, will be applied to all shard regions + /// + /// + /// The builder instance being configured. + /// + /// + /// The set of options for configuring + /// + /// + /// The same instance originally passed in. + /// + public static AkkaConfigurationBuilder WithDefaultClusterShardingSettings( + this AkkaConfigurationBuilder builder, + ShardOptions shardOptions) + { + shardOptions.DistributedData.Apply(builder); + + var sb = new StringBuilder(shardOptions.ToString()); + if (sb.Length <= 0) + return builder; + + sb.Insert(0, "akka.cluster.sharding {\n"); + sb.AppendLine("}"); + builder.AddHocon(sb.ToString(), HoconAddMode.Prepend); + + return builder; + } /// /// Starts a actor for the given entity From c43aa5d395c6a4163bf8354930c815f70c9eb4c5 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Sat, 27 Jul 2024 00:15:55 +0700 Subject: [PATCH 3/7] Update API Approver list --- .../verify/CoreApiSpec.ApproveCluster.verified.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCluster.verified.txt b/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCluster.verified.txt index c2a7ca5..4dd17f8 100644 --- a/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCluster.verified.txt +++ b/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCluster.verified.txt @@ -8,6 +8,7 @@ namespace Akka.Cluster.Hosting public static Akka.Hosting.AkkaConfigurationBuilder WithClusterClient(this Akka.Hosting.AkkaConfigurationBuilder builder, System.Collections.Generic.IEnumerable initialContactAddresses, string receptionistActorName = "receptionist") { } public static Akka.Hosting.AkkaConfigurationBuilder WithClusterClientReceptionist(this Akka.Hosting.AkkaConfigurationBuilder builder, string name = "receptionist", string? role = null) { } public static Akka.Hosting.AkkaConfigurationBuilder WithClustering(this Akka.Hosting.AkkaConfigurationBuilder builder, Akka.Cluster.Hosting.ClusterOptions? options = null) { } + public static Akka.Hosting.AkkaConfigurationBuilder WithDefaultClusterShardingSettings(this Akka.Hosting.AkkaConfigurationBuilder builder, Akka.Cluster.Hosting.ShardOptions shardOptions) { } public static Akka.Hosting.AkkaConfigurationBuilder WithDistributedData(this Akka.Hosting.AkkaConfigurationBuilder builder, Akka.Cluster.Hosting.DDataOptions options) { } public static Akka.Hosting.AkkaConfigurationBuilder WithDistributedData(this Akka.Hosting.AkkaConfigurationBuilder builder, System.Action configurator) { } public static Akka.Hosting.AkkaConfigurationBuilder WithDistributedPubSub(this Akka.Hosting.AkkaConfigurationBuilder builder, string role) { } @@ -104,6 +105,8 @@ namespace Akka.Cluster.Hosting public Akka.Persistence.Hosting.SnapshotOptions? SnapshotOptions { get; set; } public string? SnapshotPluginId { get; set; } public Akka.Cluster.Sharding.StateStoreMode? StateStoreMode { get; set; } + public Akka.Configuration.Config ToConfig() { } + public override string ToString() { } } public sealed class ShardingDDataOptions : Akka.Cluster.Hosting.DDataOptions { From 74e250e00b49db5c55dd421c3caac6c6f9393a06 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Sat, 27 Jul 2024 01:01:24 +0700 Subject: [PATCH 4/7] Do not apply DistributedData options --- .../AkkaClusterHostingExtensions.cs | 36 +++---------------- 1 file changed, 4 insertions(+), 32 deletions(-) diff --git a/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs b/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs index 8ef1e38..872e5d0 100644 --- a/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs +++ b/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs @@ -279,7 +279,7 @@ public sealed class ShardOptions /// /// /// Settings for the Distributed Data replicator. - /// The property is not used. The distributed-data + /// The property is not used. The distributed-data /// role will be the same as . /// Note that there is one Replicator per role and it's not possible /// to have different distributed-data settings for different sharding entity types. @@ -287,6 +287,9 @@ public sealed class ShardOptions /// NOTE This setting is only used when is set to /// /// + [Obsolete("This property is not being applied to the ActorSystem anymore. " + + "Use manual HOCON configuration to set \"akka.cluster.sharding.distributed-data\" values. " + + "Since v1.5.27")] public ShardingDDataOptions DistributedData { get; } = new(); /// @@ -642,35 +645,6 @@ public static AkkaConfigurationBuilder WithDistributedData( return builder; } - /// - /// Applies a default setting that, if not overriden, will be applied to all shard regions - /// - /// - /// The builder instance being configured. - /// - /// - /// The set of options for configuring - /// - /// - /// The same instance originally passed in. - /// - public static AkkaConfigurationBuilder WithDefaultClusterShardingSettings( - this AkkaConfigurationBuilder builder, - ShardOptions shardOptions) - { - shardOptions.DistributedData.Apply(builder); - - var sb = new StringBuilder(shardOptions.ToString()); - if (sb.Length <= 0) - return builder; - - sb.Insert(0, "akka.cluster.sharding {\n"); - sb.AppendLine("}"); - builder.AddHocon(sb.ToString(), HoconAddMode.Prepend); - - return builder; - } - /// /// Starts a actor for the given entity /// and registers the ShardRegion with in the @@ -874,7 +848,6 @@ public static AkkaConfigurationBuilder WithShardRegion( IMessageExtractor messageExtractor, ShardOptions shardOptions) { - shardOptions.DistributedData.Apply(builder); builder.AddHocon( ClusterSharding.DefaultConfig().WithFallback(DistributedData.DistributedData.DefaultConfig()), HoconAddMode.Append); @@ -940,7 +913,6 @@ public static AkkaConfigurationBuilder WithShardRegion( ExtractShardId extractShardId, ShardOptions shardOptions) { - shardOptions.DistributedData.Apply(builder); builder.AddHocon( ClusterSharding.DefaultConfig().WithFallback(DistributedData.DistributedData.DefaultConfig()), HoconAddMode.Append); From 2f619d14c237d49068e7df8b9e201eda80fbd53a Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Sat, 27 Jul 2024 04:00:24 +0700 Subject: [PATCH 5/7] Update API Approval list --- .../verify/CoreApiSpec.ApproveCluster.verified.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCluster.verified.txt b/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCluster.verified.txt index 4dd17f8..094d0b8 100644 --- a/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCluster.verified.txt +++ b/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCluster.verified.txt @@ -8,7 +8,6 @@ namespace Akka.Cluster.Hosting public static Akka.Hosting.AkkaConfigurationBuilder WithClusterClient(this Akka.Hosting.AkkaConfigurationBuilder builder, System.Collections.Generic.IEnumerable initialContactAddresses, string receptionistActorName = "receptionist") { } public static Akka.Hosting.AkkaConfigurationBuilder WithClusterClientReceptionist(this Akka.Hosting.AkkaConfigurationBuilder builder, string name = "receptionist", string? role = null) { } public static Akka.Hosting.AkkaConfigurationBuilder WithClustering(this Akka.Hosting.AkkaConfigurationBuilder builder, Akka.Cluster.Hosting.ClusterOptions? options = null) { } - public static Akka.Hosting.AkkaConfigurationBuilder WithDefaultClusterShardingSettings(this Akka.Hosting.AkkaConfigurationBuilder builder, Akka.Cluster.Hosting.ShardOptions shardOptions) { } public static Akka.Hosting.AkkaConfigurationBuilder WithDistributedData(this Akka.Hosting.AkkaConfigurationBuilder builder, Akka.Cluster.Hosting.DDataOptions options) { } public static Akka.Hosting.AkkaConfigurationBuilder WithDistributedData(this Akka.Hosting.AkkaConfigurationBuilder builder, System.Action configurator) { } public static Akka.Hosting.AkkaConfigurationBuilder WithDistributedPubSub(this Akka.Hosting.AkkaConfigurationBuilder builder, string role) { } @@ -90,6 +89,9 @@ namespace Akka.Cluster.Hosting public sealed class ShardOptions { public ShardOptions() { } + [System.Obsolete("This property is not being applied to the ActorSystem anymore. Use manual HOCON c" + + "onfiguration to set \"akka.cluster.sharding.distributed-data\" values. Since v1.5." + + "27")] public Akka.Cluster.Hosting.ShardingDDataOptions DistributedData { get; } public bool? FailOnInvalidEntityStateTransition { get; set; } public object? HandOffStopMessage { get; set; } From 57afee017ff25a47cdda24cabf01e7ac1174e6fa Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Tue, 30 Jul 2024 00:38:50 +0700 Subject: [PATCH 6/7] Add unit test --- .../ClusterShardingSpecs.cs | 68 +++++++++++++++++++ .../AkkaClusterHostingExtensions.cs | 19 ++++-- 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/Akka.Cluster.Hosting.Tests/ClusterShardingSpecs.cs b/src/Akka.Cluster.Hosting.Tests/ClusterShardingSpecs.cs index dc211ab..c29ded1 100644 --- a/src/Akka.Cluster.Hosting.Tests/ClusterShardingSpecs.cs +++ b/src/Akka.Cluster.Hosting.Tests/ClusterShardingSpecs.cs @@ -2,9 +2,14 @@ using System.Collections.Generic; using System.Threading.Tasks; using Akka.Actor; +using Akka.Cluster.Hosting.SBR; +using Akka.Cluster.Hosting.Tests.Lease; using Akka.Cluster.Sharding; +using Akka.Cluster.Tools.Singleton; +using Akka.Configuration; using Akka.Hosting; using FluentAssertions; +using FluentAssertions.Extensions; using Microsoft.Extensions.DependencyInjection; using Xunit; using Xunit.Abstractions; @@ -110,4 +115,67 @@ public async Task Should_use_ActorRegistry_with_ShardRegion() id.Should().Be("foo"); sourceRef.Should().Be(actorRegistry.Get()); } + + [Fact(DisplayName = "ShardOptions with different values should generate valid ClusterShardSettings")] + public void ShardOptionsTest() + { + var settings1 = ToSettings(new ShardOptions + { + RememberEntities = true, + StateStoreMode = StateStoreMode.Persistence, + RememberEntitiesStore = RememberEntitiesStore.Eventsourced, + Role = "first", + PassivateIdleEntityAfter = 1.Seconds(), + SnapshotPluginId = "firstSnapshot", + JournalPluginId = "firstJournal", + LeaseImplementation = new TestLeaseOption(), + LeaseRetryInterval = 2.Seconds(), + ShardRegionQueryTimeout = 3.Seconds(), + }); + settings1.RememberEntities.Should().BeTrue(); + settings1.StateStoreMode.Should().Be(StateStoreMode.Persistence); + settings1.RememberEntitiesStore.Should().Be(RememberEntitiesStore.Eventsourced); + settings1.Role.Should().Be("first"); + settings1.PassivateIdleEntityAfter.Should().Be(1.Seconds()); + settings1.SnapshotPluginId.Should().Be("firstSnapshot"); + settings1.JournalPluginId.Should().Be("firstJournal"); + settings1.LeaseSettings.LeaseImplementation.Should().Be("test-lease"); + settings1.LeaseSettings.LeaseRetryInterval.Should().Be(2.Seconds()); + settings1.ShardRegionQueryTimeout.Should().Be(3.Seconds()); + + var settings2 = ToSettings(new ShardOptions + { + RememberEntities = false, + StateStoreMode = StateStoreMode.DData, + RememberEntitiesStore = RememberEntitiesStore.DData, + Role = "second", + PassivateIdleEntityAfter = 4.Seconds(), + SnapshotPluginId = "secondSnapshot", + JournalPluginId = "secondJournal", + ShardRegionQueryTimeout = 5.Seconds(), + }); + settings2.RememberEntities.Should().BeFalse(); + settings2.StateStoreMode.Should().Be(StateStoreMode.DData); + settings2.RememberEntitiesStore.Should().Be(RememberEntitiesStore.DData); + settings2.Role.Should().Be("second"); + settings2.PassivateIdleEntityAfter.Should().Be(4.Seconds()); + settings2.JournalPluginId.Should().Be("secondJournal"); + settings2.SnapshotPluginId.Should().Be("secondSnapshot"); + settings2.LeaseSettings.Should().BeNull(); + settings2.ShardRegionQueryTimeout.Should().Be(5.Seconds()); + } + + private static ClusterShardingSettings ToSettings(ShardOptions shardOptions) + { + var defaultConfig = ClusterSharding.DefaultConfig() + .WithFallback(DistributedData.DistributedData.DefaultConfig()) + .WithFallback(ClusterSingletonManager.DefaultConfig()); + + var shardingConfig = ConfigurationFactory.ParseString(shardOptions.ToString()) + .WithFallback(defaultConfig.GetConfig("akka.cluster.sharding")); + var coordinatorConfig = defaultConfig.GetConfig( + shardingConfig.GetString("coordinator-singleton")); + + return ClusterShardingSettings.Create(shardingConfig, coordinatorConfig); + } } \ No newline at end of file diff --git a/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs b/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs index 872e5d0..8fa669e 100644 --- a/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs +++ b/src/Akka.Cluster.Hosting/AkkaClusterHostingExtensions.cs @@ -305,8 +305,8 @@ public sealed class ShardOptions /// or is set to false. /// public TimeSpan? PassivateIdleEntityAfter { get; set; } - - public Config ToConfig() => ToString(); + + public TimeSpan? ShardRegionQueryTimeout { get; set; } public override string ToString() { @@ -347,6 +347,9 @@ public override string ToString() else if(PassivateIdleEntityAfter is not null) sb.AppendLine($"passivate-idle-entity-after = {PassivateIdleEntityAfter.ToHocon()}"); + if (ShardRegionQueryTimeout is not null) + sb.AppendLine($"shard-region-query-timeout = {ShardRegionQueryTimeout.ToHocon()}"); + return sb.ToString(); } } @@ -849,7 +852,9 @@ public static AkkaConfigurationBuilder WithShardRegion( ShardOptions shardOptions) { builder.AddHocon( - ClusterSharding.DefaultConfig().WithFallback(DistributedData.DistributedData.DefaultConfig()), + ClusterSharding.DefaultConfig() + .WithFallback(DistributedData.DistributedData.DefaultConfig()) + .WithFallback(ClusterSingletonManager.DefaultConfig()), HoconAddMode.Append); return builder.StartActors(Resolver); @@ -857,7 +862,7 @@ public static AkkaConfigurationBuilder WithShardRegion( async Task Resolver(ActorSystem system, IActorRegistry registry, IDependencyResolver resolver) { var props = entityPropsFactory(system, registry, resolver); - var shardingConfig = shardOptions.ToConfig() + var shardingConfig = ConfigurationFactory.ParseString(shardOptions.ToString()) .WithFallback(system.Settings.Config.GetConfig("akka.cluster.sharding")); var coordinatorConfig = system.Settings.Config.GetConfig( shardingConfig.GetString("coordinator-singleton")); @@ -914,7 +919,9 @@ public static AkkaConfigurationBuilder WithShardRegion( ShardOptions shardOptions) { builder.AddHocon( - ClusterSharding.DefaultConfig().WithFallback(DistributedData.DistributedData.DefaultConfig()), + ClusterSharding.DefaultConfig() + .WithFallback(DistributedData.DistributedData.DefaultConfig()) + .WithFallback(ClusterSingletonManager.DefaultConfig()), HoconAddMode.Append); return builder.StartActors(Resolver); @@ -922,7 +929,7 @@ public static AkkaConfigurationBuilder WithShardRegion( async Task Resolver(ActorSystem system, IActorRegistry registry, IDependencyResolver resolver) { var props = entityPropsFactory(system, registry, resolver); - var shardingConfig = shardOptions.ToConfig() + var shardingConfig = ConfigurationFactory.ParseString(shardOptions.ToString()) .WithFallback(system.Settings.Config.GetConfig("akka.cluster.sharding")); var coordinatorConfig = system.Settings.Config.GetConfig( shardingConfig.GetString("coordinator-singleton")); From 3a0abf8793596a7569e274d337527a81d9f47357 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Tue, 30 Jul 2024 00:40:03 +0700 Subject: [PATCH 7/7] Update API Approval list --- .../verify/CoreApiSpec.ApproveCluster.verified.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCluster.verified.txt b/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCluster.verified.txt index 094d0b8..27e2ef4 100644 --- a/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCluster.verified.txt +++ b/src/Akka.Hosting.API.Tests/verify/CoreApiSpec.ApproveCluster.verified.txt @@ -103,11 +103,11 @@ namespace Akka.Cluster.Hosting public bool? RememberEntities { get; set; } public Akka.Cluster.Sharding.RememberEntitiesStore? RememberEntitiesStore { get; set; } public string? Role { get; set; } + public System.TimeSpan? ShardRegionQueryTimeout { get; set; } public bool? ShouldPassivateIdleEntities { get; set; } public Akka.Persistence.Hosting.SnapshotOptions? SnapshotOptions { get; set; } public string? SnapshotPluginId { get; set; } public Akka.Cluster.Sharding.StateStoreMode? StateStoreMode { get; set; } - public Akka.Configuration.Config ToConfig() { } public override string ToString() { } } public sealed class ShardingDDataOptions : Akka.Cluster.Hosting.DDataOptions