diff --git a/README.md b/README.md
index 556b4b850b9..aa83425061a 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,43 @@
# Akka.NET
-
+
-[](https://gitter.im/akkadotnet/akka.net?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[](https://gitter.im/akkadotnet/akka.net?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-**Akka.NET** is a professional-grade port of the popular Java/Scala framework [Akka](http://akka.io) distributed actor framework to .NET.
+**[Akka.NET](https://getakka.net/)** is a .NET port of the popular [Akka project](https://akka.io/) from the Scala / Java community. We are an idiomatic [.NET implementation of the actor model](https://petabridge.com/blog/akkadotnet-what-is-an-actor/) built on top of the .NET Common Language Runtime.
+
+* **Website**: [https://getakka.net/](https://getakka.net/)
+* **Twitter** 🐦: [AkkaDotNet](https://twitter.com/AkkaDotNet)
+* **Discussions** 📣: [Akka.NET GitHub Discussions](https://github.com/akkadotnet/akka.net/discussions)
+* **Chat** 💬: [Akka.NET on Discord](https://discord.gg/GSCfPwhbWP)
+* **StackOverflow** ✔️: [Akka.NET on StackOverflow](https://stackoverflow.com/questions/tagged/akka.net)
Akka.NET is a [.NET Foundation](https://dotnetfoundation.org/) project.
-
+
+
+## How is Akka.NET Used?
+
+Akka.NET can be used in-process or inside large, distributed real-time systems; we support a wide variety of use cases.
+
+Akka.NET can be used to solve the following types of problems:
+
+1. **Concurrency** - Akka.NET actors only process messages one-at-a-time and they do so in first in, first out (FIFO) order; this means that any application state internal to an actor is automatically thread-safe without having to use `lock`s or any other shared-memory synchronization mechanisms.
+2. **Stream Processing** - Akka.NET actors and [Akka.Streams](https://getakka.net/articles/streams/introduction.html) make it easy to build streaming applications, used for processing incoming streams of data or incoming streams of live events such as UI or network events inside native applications.
+3. **Event-Driven Programming** - actors make it easy to build event-driven applications, as actors' message-processing routines naturally express these types of designs.
+4. **Event Sourcing and CQRS** - [Akka.Persistence](https://getakka.net/articles/persistence/architecture.html), used by actors to make their state re-entrant and recoverable across restarts or migrations between nodes, natively supports event sourcing. [Akka.Persistence.Query](https://getakka.net/articles/persistence/persistence-query.html) can be used to compute CQRS-style projections and materialized views from Akka.Persistence data.
+5. **Location Transparency** - [Akka.Remote](https://getakka.net/articles/remoting/index.html) makes it simple for actors in remote processes to transparently communicate with each other.
+6. **Highly Available, Fault-Tolerant Distributed Systems** - [Akka.Cluster](https://getakka.net/articles/clustering/cluster-overview.html), [Akka.Cluster.Sharding](https://getakka.net/articles/clustering/cluster-sharding.html), and other tools built on top of Akka.Cluster make it possible to build highly available and fault-tolerant distributed systems by leveraging peer-to-peer programming models with topology-aware message routing and distribution.
+7. **Low Latency, High Throughput** - Akka.NET aims to be low latency and high throughput, processing 10s millions of messages per second in-memory and hundreds of thousands of messages per second over remote connections.
+
+## Where Can I Learn Akka.NET?
+
+You can start by taking the [Akka.NET Bootcamp](https://learnakka.net/), but there are many other great [learning resources for Akka.NET Online](https://getakka.net/community/online-resources.html).
+
+* [Petabridge's Akka.NET Videos on YouTube](https://www.youtube.com/c/PetabridgeAcademy)
+* "[.NET Conf - When and How to Use the Actor Model An Introduction to Akka.NET Actors](https://www.youtube.com/watch?v=0KnIMDoJpZs)"
+* _[Reactive Applications with Akka.NET](https://www.manning.com/books/reactive-applications-with-akka-net)_
+* _[Akka.NET Succinctly](https://www.syncfusion.com/succinctly-free-ebooks/akka-net-succinctly)_
## Build Status
@@ -25,12 +54,7 @@ Akka.NET is a [.NET Foundation](https://dotnetfoundation.org/) project.
| Docs | [](https://dev.azure.com/petabridge/akkadotnet-tools/_build/latest?definitionId=82&branchName=dev) |
-### Documentation and resources
-
-#### [Akka.NET Project Site](http://getakka.net)
-
-
-### Install Akka.NET via NuGet
+## Install Akka.NET via NuGet
If you want to include Akka.NET in your project, you can [install it directly from NuGet](https://www.nuget.org/packages/Akka)
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 1cbe87146a8..27595960db5 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,3 +1,19 @@
+#### 1.4.42 September 23 2022 ####
+Akka.NET v1.4.42 is a minor release that contains some minor bug fixes.
+
+* [DData: Suppress gossip message from showing up in debug log unless verbose debug logging is turned on](https://github.com/akkadotnet/akka.net/issues/6091)
+* [TestKit: TestKit automatically injects the default TestKit default configuration if an ActorSystem is passed into its constructor](https://github.com/akkadotnet/akka.net/issues/6094)
+* [Sharding: Added a new `GetEntityLocation` query message to retrieve an entity address location in the shard region](https://github.com/akkadotnet/akka.net/issues/6101)
+
+ In order to use this query, "remember entities" should be turned on _or_ the provided shard `IMessageExtractor` supports the `ShardRegion.StartEntity` message. Complete documentation can be read [here](https://getakka.net/articles/clustering/cluster-sharding.html#querying-for-the-location-of-specific-entities)
+
+If you want to see the [full set of changes made in Akka.NET v1.4.42, click here](https://github.com/akkadotnet/akka.net/milestone/73).
+
+| COMMITS | LOC+ | LOC- | AUTHOR |
+|---------|------|------|---------------------|
+| 3 | 66 | 3 | Gregorius Soedharmo |
+| 1 | 557 | 118 | Aaron Stannard |
+
#### 1.4.41 August 31 2022 ####
Akka.NET v1.4.41 is a minor release that contains some minor bug fix and throughput performance improvement for Akka.Remote
diff --git a/docs/articles/clustering/cluster-sharding.md b/docs/articles/clustering/cluster-sharding.md
index 36a58dc8f92..759e6cbe43f 100644
--- a/docs/articles/clustering/cluster-sharding.md
+++ b/docs/articles/clustering/cluster-sharding.md
@@ -165,13 +165,6 @@ Possible reasons for disabling remember entity storage are:
For supporting remembered entities in an environment without disk storage but with access to a database, use persistence mode instead.
-> [!NOTE]
-> Currently, Lightning.NET library, the storage solution used to store DData in disk, is having problem
-> deploying native library files in [Linux operating system operating in x64 and ARM platforms]
-> ().
->
-> You will need to install LightningDB in your Linux distribution manually if you wanted to use the durable DData feature.
-
### Terminating Remembered Entities
One complication that `akka.cluster.sharding.remember-entities = true` introduces is that your sharded entity actors can no longer be terminated through the normal Akka.NET channels, i.e. `Context.Stop(Self)`, `PoisonPill.Instance`, and the like. This is because as part of the `remember-entities` contract - the sharding system is going to insist on keeping all remembered entities alive until explicitly told to stop.
@@ -217,6 +210,19 @@ You can inspect current sharding stats by using following messages:
* On `GetShardRegionState` shard region will reply with `ShardRegionState` containing data about shards living in the current actor system and what entities are alive on each one of them.
* On `GetClusterShardingStats` shard region will reply with `ClusterShardingStats` having information about shards living in the whole cluster and how many entities alive in each one of them.
+### Querying for the Location of Specific Entities
+
+It's possible to query a `ShardRegion` or a `ShardRegionProxy` using a `GetEntityLocation` query:
+
+[!code-csharp[ShardedDaemonProcessSpec.cs](../../../src/contrib/cluster/Akka.Cluster.Sharding.Tests/ShardRegionQueriesSpecs.cs?name=GetEntityLocationQuery)]
+
+A `GetEntityLocation` query will always return an `EntityLocation` response - even if the query could not be executed.
+
+> [!IMPORTANT]
+> One major caveat is that in order for the `GetEntityLocation` to execute your `IMessageExtractor` or `ShardExtractor` delegate will need to support the `ShardRegion.StartEntity` message - just like you'd have to use in order to support `remember-entities=on`:
+
+[!code-csharp[ShardedDaemonProcessSpec.cs](../../../src/contrib/cluster/Akka.Cluster.Sharding.Tests/ShardRegionQueriesSpecs.cs?name=GetEntityLocationExtractor)]
+
## Integrating Cluster Sharding with Persistent Actors
One of the most common scenarios, where cluster sharding is used, is to combine them with event-sourced persistent actors from [Akka.Persistence](xref:persistence-architecture) module.
diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/ShardRegionQueriesSpecs.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/ShardRegionQueriesSpecs.cs
new file mode 100644
index 00000000000..d4263d88d10
--- /dev/null
+++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/ShardRegionQueriesSpecs.cs
@@ -0,0 +1,183 @@
+//-----------------------------------------------------------------------
+//
+// Copyright (C) 2009-2022 Lightbend Inc.
+// Copyright (C) 2013-2022 .NET Foundation
+//
+//-----------------------------------------------------------------------
+
+using System;
+using System.Threading.Tasks;
+using Akka.Actor;
+using Akka.Cluster.Tools.Singleton;
+using Akka.Configuration;
+using Akka.TestKit;
+using Akka.TestKit.TestActors;
+using Akka.Util;
+using Xunit;
+using Xunit.Abstractions;
+using FluentAssertions;
+
+namespace Akka.Cluster.Sharding.Tests
+{
+ public class ShardRegionQueriesSpecs : AkkaSpec
+ {
+ private Cluster _cluster;
+ private ClusterSharding _clusterSharding;
+ private IActorRef _shardRegion;
+
+ private ActorSystem _proxySys;
+
+ public ShardRegionQueriesSpecs(ITestOutputHelper outputHelper) : base(GetConfig(), outputHelper)
+ {
+ _clusterSharding = ClusterSharding.Get(Sys);
+ _cluster = Cluster.Get(Sys);
+ _shardRegion = _clusterSharding.Start("entity", s => EchoActor.Props(this, true),
+ ClusterShardingSettings.Create(Sys).WithRole("shard"), ExtractEntityId, ExtractShardId);
+
+ var proxySysConfig = ConfigurationFactory.ParseString("akka.cluster.roles = [proxy]")
+ .WithFallback(Sys.Settings.Config);
+ _proxySys = ActorSystem.Create(Sys.Name, proxySysConfig);
+
+ _cluster.Join(_cluster.SelfAddress);
+ AwaitAssert(() => { _cluster.SelfMember.Status.ShouldBe(MemberStatus.Up); });
+
+ // form a 2-node cluster
+ var proxyCluster = Cluster.Get(_proxySys);
+ proxyCluster.Join(_cluster.SelfAddress);
+ AwaitAssert(() => { proxyCluster.SelfMember.Status.ShouldBe(MemberStatus.Up); });
+ }
+
+ protected override void AfterAll()
+ {
+ Shutdown(_proxySys);
+ base.AfterAll();
+ }
+
+ private Option<(string, object)> ExtractEntityId(object message)
+ {
+ switch (message)
+ {
+ case int i:
+ return (i.ToString(), message);
+ }
+
+ throw new NotSupportedException();
+ }
+
+ //
+ private string ExtractShardId(object message)
+ {
+ switch (message)
+ {
+ case int i:
+ return (i % 10).ToString();
+ // must support ShardRegion.StartEntity in order for
+ // GetEntityLocation to work properly
+ case ShardRegion.StartEntity se:
+ return se.EntityId;
+ }
+
+ throw new NotSupportedException();
+ }
+ //
+
+ private static Config GetConfig()
+ {
+ return ConfigurationFactory.ParseString(@"
+ akka.loglevel = WARNING
+ akka.actor.provider = cluster
+ akka.remote.dot-netty.tcp.port = 0
+ akka.cluster.roles = [shard]")
+ .WithFallback(Sharding.ClusterSharding.DefaultConfig())
+ .WithFallback(DistributedData.DistributedData.DefaultConfig())
+ .WithFallback(ClusterSingletonManager.DefaultConfig());
+ }
+
+ ///
+ /// DocFx material for demonstrating how this query type works
+ ///
+ [Fact]
+ public async Task ShardRegion_GetEntityLocation_DocumentationSpec()
+ {
+ //
+ // creates an entity with entityId="1"
+ await _shardRegion.Ask(1, TimeSpan.FromSeconds(3));
+
+ // determine where entity with "entityId=1" is located in cluster
+ var q1 = await _shardRegion.Ask(new GetEntityLocation("1", TimeSpan.FromSeconds(1)));
+
+ q1.EntityId.Should().Be("1");
+
+ // have a valid ShardId
+ q1.ShardId.Should().NotBeEmpty();
+
+ // have valid address for node that will / would host entity
+ q1.ShardRegion.Should().NotBe(Address.AllSystems); // has real address
+
+ // if entity actor is alive, will retrieve a reference to it
+ q1.EntityRef.HasValue.Should().BeTrue();
+ //
+ }
+
+ [Fact(DisplayName = "ShardRegion should support GetEntityLocation queries locally")]
+ public async Task ShardRegion_should_support_GetEntityLocation_query_locally()
+ {
+ // arrange
+ await _shardRegion.Ask(1, TimeSpan.FromSeconds(3));
+ await _shardRegion.Ask(2, TimeSpan.FromSeconds(3));
+
+ // act
+ var q1 = await _shardRegion.Ask(new GetEntityLocation("1", TimeSpan.FromSeconds(1)));
+ var q2 = await _shardRegion.Ask(new GetEntityLocation("2", TimeSpan.FromSeconds(1)));
+ var q3 = await _shardRegion.Ask(new GetEntityLocation("3", TimeSpan.FromSeconds(1)));
+
+ // assert
+ void AssertValidEntityLocation(EntityLocation e, string entityId)
+ {
+ e.EntityId.Should().Be(entityId);
+ e.EntityRef.Should().NotBe(Option.None);
+ e.ShardId.Should().NotBeNullOrEmpty();
+ e.ShardRegion.Should().Be(_cluster.SelfAddress);
+ }
+
+ AssertValidEntityLocation(q1, "1");
+ AssertValidEntityLocation(q2, "2");
+
+ q3.EntityRef.Should().Be(Option.None);
+ q3.ShardId.Should().NotBeNullOrEmpty(); // should still have computed a valid shard?
+ q3.ShardRegion.Should().Be(Address.AllSystems);
+ }
+
+ [Fact(DisplayName = "ShardRegion should support GetEntityLocation queries remotely")]
+ public async Task ShardRegion_should_support_GetEntityLocation_query_remotely()
+ {
+ // arrange
+ var sharding2 = ClusterSharding.Get(_proxySys);
+ var shardRegionProxy = await sharding2.StartProxyAsync("entity", "shard", ExtractEntityId, ExtractShardId);
+
+ await shardRegionProxy.Ask(1, TimeSpan.FromSeconds(3));
+ await shardRegionProxy.Ask(2, TimeSpan.FromSeconds(3));
+
+ // act
+ var q1 = await shardRegionProxy.Ask(new GetEntityLocation("1", TimeSpan.FromSeconds(1)));
+ var q2 = await shardRegionProxy.Ask(new GetEntityLocation("2", TimeSpan.FromSeconds(1)));
+ var q3 = await shardRegionProxy.Ask(new GetEntityLocation("3", TimeSpan.FromSeconds(1)));
+
+ // assert
+ void AssertValidEntityLocation(EntityLocation e, string entityId)
+ {
+ e.EntityId.Should().Be(entityId);
+ e.EntityRef.Should().NotBe(Option.None);
+ e.ShardId.Should().NotBeNullOrEmpty();
+ e.ShardRegion.Should().Be(_cluster.SelfAddress);
+ }
+
+ AssertValidEntityLocation(q1, "1");
+ AssertValidEntityLocation(q2, "2");
+
+ q3.EntityRef.Should().Be(Option.None);
+ q3.ShardId.Should().NotBeNullOrEmpty(); // should still have computed a valid shard?
+ q3.ShardRegion.Should().Be(Address.AllSystems);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/contrib/cluster/Akka.Cluster.Sharding/Akka.Cluster.Sharding.csproj b/src/contrib/cluster/Akka.Cluster.Sharding/Akka.Cluster.Sharding.csproj
index 8234137e52c..ec62248e18c 100644
--- a/src/contrib/cluster/Akka.Cluster.Sharding/Akka.Cluster.Sharding.csproj
+++ b/src/contrib/cluster/Akka.Cluster.Sharding/Akka.Cluster.Sharding.csproj
@@ -3,7 +3,7 @@
Akka.Cluster.Sharding
- Sharded actors with managed lifecycle for Akka.NET cluster
+ Sharded actors with managed lifecycle for Akka.NET cluster. Used to distribute state in a fault-tolerant, consistent fashion over an Akka.NET cluster.$(NetStandardLibVersion)$(AkkaPackageTags);network;cluster;shardingtrue
diff --git a/src/contrib/cluster/Akka.Cluster.Sharding/ShardRegion.cs b/src/contrib/cluster/Akka.Cluster.Sharding/ShardRegion.cs
index b274fe145ce..f034e71238a 100644
--- a/src/contrib/cluster/Akka.Cluster.Sharding/ShardRegion.cs
+++ b/src/contrib/cluster/Akka.Cluster.Sharding/ShardRegion.cs
@@ -13,7 +13,9 @@
using Akka.Actor;
using Akka.Event;
using Akka.Pattern;
+using Akka.Util;
using Akka.Util.Internal;
+using Get = Akka.DistributedData.Get;
namespace Akka.Cluster.Sharding
{
@@ -42,7 +44,10 @@ internal sealed class Retry : IShardRegionCommand
/// TBD
///
public static readonly Retry Instance = new Retry();
- private Retry() { }
+
+ private Retry()
+ {
+ }
}
///
@@ -62,7 +67,10 @@ internal sealed class RegisterRetry : IShardRegionCommand
/// TBD
///
public static readonly RegisterRetry Instance = new RegisterRetry();
- private RegisterRetry() { }
+
+ private RegisterRetry()
+ {
+ }
}
///
@@ -76,6 +84,7 @@ internal sealed class RestartShard
/// TBD
///
public readonly ShardId ShardId;
+
///
/// TBD
///
@@ -111,7 +120,6 @@ public StartEntity(EntityId entityId)
#region Equals
-
public override bool Equals(object obj)
{
var other = obj as StartEntity;
@@ -122,7 +130,7 @@ public override bool Equals(object obj)
return EntityId.Equals(other.EntityId);
}
-
+
public override int GetHashCode()
{
unchecked
@@ -165,7 +173,6 @@ public StartEntityAck(EntityId entityId, ShardId shardId)
#region Equals
-
public override bool Equals(object obj)
{
var other = obj as StartEntityAck;
@@ -174,10 +181,10 @@ public override bool Equals(object obj)
if (ReferenceEquals(other, this)) return true;
return EntityId.Equals(other.EntityId)
- && ShardId.Equals(other.ShardId);
+ && ShardId.Equals(other.ShardId);
}
-
+
public override int GetHashCode()
{
unchecked
@@ -219,10 +226,14 @@ private StopTimeoutWarning()
private static readonly TimeSpan StopTimeoutWarningAfter = TimeSpan.FromSeconds(5);
private ILoggingAdapter _log;
+
///
/// TBD
///
- public ILoggingAdapter Log { get { return _log ?? (_log = Context.GetLogger()); } }
+ public ILoggingAdapter Log
+ {
+ get { return _log ?? (_log = Context.GetLogger()); }
+ }
public ITimerScheduler Timers { get; set; }
@@ -236,9 +247,12 @@ private StopTimeoutWarning()
/// TBD
/// TBD
/// TBD
- public static Props Props(string typeName, ShardId shard, IActorRef replyTo, IEnumerable entities, object stopMessage, TimeSpan handoffTimeout)
+ public static Props Props(string typeName, ShardId shard, IActorRef replyTo,
+ IEnumerable entities, object stopMessage, TimeSpan handoffTimeout)
{
- return Actor.Props.Create(() => new HandOffStopper(typeName, shard, replyTo, entities, stopMessage, handoffTimeout)).WithDeploy(Deploy.Local);
+ return Actor.Props
+ .Create(() => new HandOffStopper(typeName, shard, replyTo, entities, stopMessage, handoffTimeout))
+ .WithDeploy(Deploy.Local);
}
///
@@ -252,7 +266,8 @@ public static Props Props(string typeName, ShardId shard, IActorRef replyTo, IEn
/// TBD
/// TBD
/// TBD
- public HandOffStopper(string typeName, ShardId shard, IActorRef replyTo, IEnumerable entities, object stopMessage, TimeSpan handoffTimeout)
+ public HandOffStopper(string typeName, ShardId shard, IActorRef replyTo, IEnumerable entities,
+ object stopMessage, TimeSpan handoffTimeout)
{
var remaining = new HashSet(entities);
@@ -273,20 +288,23 @@ public HandOffStopper(string typeName, ShardId shard, IActorRef replyTo, IEnumer
shard,
StopTimeoutWarningAfter,
stopMessage.GetType(),
- (CoordinatedShutdown.Get(Context.System).ShutdownReason != null) ?
- "" // the region will be shutdown earlier so would be confusing to say more
+ (CoordinatedShutdown.Get(Context.System).ShutdownReason != null)
+ ? "" // the region will be shutdown earlier so would be confusing to say more
: $"Waiting additional [{handoffTimeout}] before stopping the remaining entities.");
});
Receive(s =>
{
- Log.Warning($"{typeName}: HandOffStopMessage[{{0}}] is not handled by some of the entities in shard [{{1}}] after [{{2}}], " +
- "stopping the remaining [{3}] entities.", stopMessage.GetType(), shard, handoffTimeout, remaining.Count);
+ Log.Warning(
+ $"{typeName}: HandOffStopMessage[{{0}}] is not handled by some of the entities in shard [{{1}}] after [{{2}}], " +
+ "stopping the remaining [{3}] entities.", stopMessage.GetType(), shard, handoffTimeout,
+ remaining.Count);
foreach (var r in remaining)
Context.Stop(r);
});
- Timers.StartSingleTimer(StopTimeoutWarning.Instance, StopTimeoutWarning.Instance, StopTimeoutWarningAfter);
+ Timers.StartSingleTimer(StopTimeoutWarning.Instance, StopTimeoutWarning.Instance,
+ StopTimeoutWarningAfter);
Timers.StartSingleTimer(StopTimeout.Instance, StopTimeout.Instance, handoffTimeout);
foreach (var aref in remaining)
@@ -310,9 +328,13 @@ public HandOffStopper(string typeName, ShardId shard, IActorRef replyTo, IEnumer
///
///
/// TBD
- internal static Props Props(string typeName, Func entityProps, ClusterShardingSettings settings, string coordinatorPath, ExtractEntityId extractEntityId, ExtractShardId extractShardId, object handOffStopMessage, IActorRef replicator, int majorityMinCap)
+ internal static Props Props(string typeName, Func entityProps, ClusterShardingSettings settings,
+ string coordinatorPath, ExtractEntityId extractEntityId, ExtractShardId extractShardId,
+ object handOffStopMessage, IActorRef replicator, int majorityMinCap)
{
- return Actor.Props.Create(() => new ShardRegion(typeName, entityProps, settings, coordinatorPath, extractEntityId, extractShardId, handOffStopMessage, replicator, majorityMinCap)).WithDeploy(Deploy.Local);
+ return Actor.Props.Create(() => new ShardRegion(typeName, entityProps, settings, coordinatorPath,
+ extractEntityId, extractShardId, handOffStopMessage, replicator, majorityMinCap))
+ .WithDeploy(Deploy.Local);
}
///
@@ -326,35 +348,43 @@ internal static Props Props(string typeName, Func entityProps, Cl
///
///
/// TBD
- internal static Props ProxyProps(string typeName, ClusterShardingSettings settings, string coordinatorPath, ExtractEntityId extractEntityId, ExtractShardId extractShardId, IActorRef replicator, int majorityMinCap)
+ internal static Props ProxyProps(string typeName, ClusterShardingSettings settings, string coordinatorPath,
+ ExtractEntityId extractEntityId, ExtractShardId extractShardId, IActorRef replicator, int majorityMinCap)
{
- return Actor.Props.Create(() => new ShardRegion(typeName, null, settings, coordinatorPath, extractEntityId, extractShardId, PoisonPill.Instance, replicator, majorityMinCap)).WithDeploy(Deploy.Local);
+ return Actor.Props.Create(() => new ShardRegion(typeName, null, settings, coordinatorPath, extractEntityId,
+ extractShardId, PoisonPill.Instance, replicator, majorityMinCap)).WithDeploy(Deploy.Local);
}
///
/// TBD
///
public readonly string TypeName;
+
///
/// TBD
///
public readonly Func EntityProps;
+
///
/// TBD
///
public readonly ClusterShardingSettings Settings;
+
///
/// TBD
///
public readonly string CoordinatorPath;
+
///
/// TBD
///
public readonly ExtractEntityId ExtractEntityId;
+
///
/// TBD
///
public readonly ExtractShardId ExtractShardId;
+
///
/// TBD
///
@@ -371,35 +401,46 @@ internal static Props ProxyProps(string typeName, ClusterShardingSettings settin
///
/// TBD
///
- protected IImmutableSet MembersByAge = ImmutableSortedSet.Empty.WithComparer(Member.AgeOrdering);
+ protected IImmutableSet
+ MembersByAge = ImmutableSortedSet.Empty.WithComparer(Member.AgeOrdering);
// membersByAge contains members with these status
- private static readonly ImmutableHashSet MemberStatusOfInterest = ImmutableHashSet.Create(MemberStatus.Up, MemberStatus.Leaving, MemberStatus.Exiting);
+ private static readonly ImmutableHashSet MemberStatusOfInterest =
+ ImmutableHashSet.Create(MemberStatus.Up, MemberStatus.Leaving, MemberStatus.Exiting);
///
/// TBD
///
- protected IImmutableDictionary> Regions = ImmutableDictionary>.Empty;
+ protected IImmutableDictionary> Regions =
+ ImmutableDictionary>.Empty;
+
///
/// TBD
///
- protected IImmutableDictionary RegionByShard = ImmutableDictionary.Empty;
+ protected IImmutableDictionary
+ RegionByShard = ImmutableDictionary.Empty;
+
///
/// TBD
///
- protected IImmutableDictionary>> ShardBuffers = ImmutableDictionary>>.Empty;
+ protected IImmutableDictionary>> ShardBuffers =
+ ImmutableDictionary>>.Empty;
+
///
/// TBD
///
protected IImmutableDictionary Shards = ImmutableDictionary.Empty;
+
///
/// TBD
///
protected IImmutableDictionary ShardsByRef = ImmutableDictionary.Empty;
+
///
/// TBD
///
protected IImmutableSet StartingShards = ImmutableHashSet.Empty;
+
///
/// TBD
///
@@ -428,7 +469,9 @@ internal static Props ProxyProps(string typeName, ClusterShardingSettings settin
/// TBD
///
///
- public ShardRegion(string typeName, Func entityProps, ClusterShardingSettings settings, string coordinatorPath, ExtractEntityId extractEntityId, ExtractShardId extractShardId, object handOffStopMessage, IActorRef replicator, int majorityMinCap)
+ public ShardRegion(string typeName, Func entityProps, ClusterShardingSettings settings,
+ string coordinatorPath, ExtractEntityId extractEntityId, ExtractShardId extractShardId,
+ object handOffStopMessage, IActorRef replicator, int majorityMinCap)
{
TypeName = typeName;
EntityProps = entityProps;
@@ -465,10 +508,14 @@ private void SetupCoordinatedShutdown()
}
private ILoggingAdapter _log;
+
///
/// TBD
///
- public ILoggingAdapter Log { get { return _log ?? (_log = Context.GetLogger()); } }
+ public ILoggingAdapter Log
+ {
+ get { return _log ?? (_log = Context.GetLogger()); }
+ }
public ITimerScheduler Timers { get; set; }
@@ -476,10 +523,14 @@ private void SetupCoordinatedShutdown()
/// TBD
///
public bool GracefulShutdownInProgress { get; private set; }
+
///
/// TBD
///
- public int TotalBufferSize { get { return ShardBuffers.Aggregate(0, (acc, entity) => acc + entity.Value.Count); } }
+ public int TotalBufferSize
+ {
+ get { return ShardBuffers.Aggregate(0, (acc, entity) => acc + entity.Value.Count); }
+ }
///
/// When leaving the coordinator singleton is started rather quickly on next
@@ -583,7 +634,6 @@ protected override bool Receive(object message)
{
switch (message)
{
-
case Terminated t:
HandleTerminated(t);
return true;
@@ -615,7 +665,8 @@ protected override bool Receive(object message)
DeliverMessage(message, Sender);
return true;
default:
- Log.Warning("{0}: Message does not have an extractor defined in shard so it was ignored: {1}", TypeName, message);
+ Log.Warning("{0}: Message does not have an extractor defined in shard so it was ignored: {1}",
+ TypeName, message);
return false;
}
}
@@ -669,7 +720,8 @@ private void Register()
{
if (Log.IsWarningEnabled)
{
- Log.Warning("{0}: Trying to register to coordinator at [{1}], but no acknowledgement. Total [{2}] buffered messages. [{3}]",
+ Log.Warning(
+ "{0}: Trying to register to coordinator at [{1}], but no acknowledgement. Total [{2}] buffered messages. [{3}]",
TypeName,
string.Join(", ", actorSelections.Select(i => i.PathString)),
TotalBufferSize,
@@ -678,7 +730,8 @@ private void Register()
}
else if (Log.IsDebugEnabled)
{
- Log.Debug("{0}: Trying to register to coordinator at [{1}], but no acknowledgement. No buffered messages yet. [{2}]",
+ Log.Debug(
+ "{0}: Trying to register to coordinator at [{1}], but no acknowledgement. No buffered messages yet. [{2}]",
TypeName,
string.Join(", ", actorSelections.Select(i => i.PathString)),
coordinatorMessage);
@@ -716,7 +769,9 @@ private void DeliverStartEntity(object message, IActorRef sender)
catch (Exception ex)
{
//case ex: MatchError ⇒
- Log.Error(ex, "{0}: When using remember-entities the shard id extractor must handle ShardRegion.StartEntity(id).", TypeName);
+ Log.Error(ex,
+ "{0}: When using remember-entities the shard id extractor must handle ShardRegion.StartEntity(id).",
+ TypeName);
}
}
@@ -739,8 +794,10 @@ private void DeliverMessage(object message, IActorRef sender)
_coordinator?.Tell(new PersistentShardCoordinator.GetShardHome(shardId));
}
- Log.Debug("{0}: Buffer message for shard [{1}]. Total [{2}] buffered messages.", TypeName, shardId, buffer.Count + 1);
- ShardBuffers = ShardBuffers.SetItem(shardId, buffer.Add(new KeyValuePair