diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/CoordinatedShutdownShardingSpec.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/CoordinatedShutdownShardingSpec.cs index cb273732940..a9b45d39b54 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/CoordinatedShutdownShardingSpec.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/CoordinatedShutdownShardingSpec.cs @@ -96,10 +96,11 @@ public CoordinatedShutdownShardingSpec(ITestOutputHelper helper) : base(SpecConf }); } - protected override void BeforeTermination() + protected override async Task AfterAllAsync() { - Shutdown(_sys1); - Shutdown(_sys2); + await base.AfterAllAsync(); + await ShutdownAsync(_sys1); + await ShutdownAsync(_sys2); } /// diff --git a/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonLeavingSpeedSpec.cs b/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonLeavingSpeedSpec.cs index 7b53ff4d2cc..5d86f28a8ff 100644 --- a/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonLeavingSpeedSpec.cs +++ b/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonLeavingSpeedSpec.cs @@ -160,10 +160,11 @@ await AwaitAssertAsync(() => } } - protected override void AfterTermination() + protected override async Task AfterAllAsync() { + await base.AfterAllAsync(); foreach (var s in _systems) - Shutdown(s); + await ShutdownAsync(s); } } } diff --git a/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonRestart2Spec.cs b/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonRestart2Spec.cs index 4eb1099866c..5e0d7faa8ad 100644 --- a/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonRestart2Spec.cs +++ b/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonRestart2Spec.cs @@ -125,13 +125,14 @@ public void Restarting_cluster_node_during_hand_over_must_restart_singletons_in_ }); } - protected override void AfterTermination() + protected override async Task AfterAllAsync() { - Shutdown(_sys1); - Shutdown(_sys2); - Shutdown(_sys3); + await base.AfterAllAsync(); + await ShutdownAsync(_sys1); + await ShutdownAsync(_sys2); + await ShutdownAsync(_sys3); if (_sys4 != null) - Shutdown(_sys4); + await ShutdownAsync(_sys4); } public class Singleton : ReceiveActor diff --git a/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonRestartSpec.cs b/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonRestartSpec.cs index 66caaa21553..bb52aaefbce 100644 --- a/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonRestartSpec.cs +++ b/src/contrib/cluster/Akka.Cluster.Tools.Tests/Singleton/ClusterSingletonRestartSpec.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Immutable; using System.Linq; +using System.Threading.Tasks; using Akka.Actor; using Akka.Cluster.Tools.Singleton; using Akka.Configuration; @@ -128,12 +129,13 @@ public void Restarting_cluster_node_with_same_hostname_and_port_must_handover_to }); } - protected override void AfterTermination() + protected override async Task AfterAllAsync() { - Shutdown(_sys1); - Shutdown(_sys2); + await base.AfterAllAsync(); + await ShutdownAsync(_sys1); + await ShutdownAsync(_sys2); if(_sys3 != null) - Shutdown(_sys3); + await ShutdownAsync(_sys3); } /// diff --git a/src/contrib/cluster/Akka.DistributedData.Tests/ReplicatorSpecs.cs b/src/contrib/cluster/Akka.DistributedData.Tests/ReplicatorSpecs.cs index bd52b70f7eb..5b3b779b940 100644 --- a/src/contrib/cluster/Akka.DistributedData.Tests/ReplicatorSpecs.cs +++ b/src/contrib/cluster/Akka.DistributedData.Tests/ReplicatorSpecs.cs @@ -574,12 +574,12 @@ await AwaitAssertAsync(async () => }); } - - protected override void BeforeTermination() + protected override async Task AfterAllAsync() { - Shutdown(_sys1); - Shutdown(_sys2); - Shutdown(_sys3); + await base.AfterAllAsync(); + await ShutdownAsync(_sys1); + await ShutdownAsync(_sys2); + await ShutdownAsync(_sys3); GC.Collect(); } diff --git a/src/contrib/testkits/Akka.TestKit.Xunit2/TestKit.cs b/src/contrib/testkits/Akka.TestKit.Xunit2/TestKit.cs index 2d79dab4b4d..e906860fa4b 100644 --- a/src/contrib/testkits/Akka.TestKit.Xunit2/TestKit.cs +++ b/src/contrib/testkits/Akka.TestKit.Xunit2/TestKit.cs @@ -6,11 +6,13 @@ //----------------------------------------------------------------------- using System; +using System.Threading.Tasks; using Akka.Actor; using Akka.Actor.Setup; using Akka.Configuration; using Akka.Event; using Akka.TestKit.Xunit2.Internals; +using Xunit; using Xunit.Abstractions; namespace Akka.TestKit.Xunit2 @@ -19,10 +21,8 @@ namespace Akka.TestKit.Xunit2 /// This class represents an Akka.NET TestKit that uses xUnit /// as its testing framework. /// - public class TestKit : TestKitBase , IDisposable + public class TestKit : TestKitBase, IAsyncLifetime { - private bool _isDisposed; //Automatically initialized to false; - /// /// The provider used to write test output. /// @@ -104,14 +104,13 @@ public TestKit(string config, ITestOutputHelper output = null) /// This method is called when a test ends. /// /// - /// If you override this, then make sure you either call base.AfterTest() or - /// TestKitBase.Shutdown + /// If you override this, then make sure you either call base.AfterAllAsync() /// to shut down the system. Otherwise a memory leak will occur. /// /// - protected virtual void AfterAll() + protected virtual async Task AfterAllAsync() { - Shutdown(); + await ShutdownAsync(); } /// @@ -128,42 +127,14 @@ protected void InitializeLogger(ActorSystem system) } } - - public void Dispose() + public virtual Task InitializeAsync() { - Dispose(true); - //Take this object off the finalization queue and prevent finalization code for this object - //from executing a second time. - GC.SuppressFinalize(this); + return Task.CompletedTask; } - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - /// - /// if set to true the method has been called directly or indirectly by a user's code. - /// Managed and unmanaged resources will be disposed.
if set to false the method - /// has been called by the runtime from inside the finalizer and only unmanaged resources can - /// be disposed. - /// - protected virtual void Dispose(bool disposing) + public virtual async Task DisposeAsync() { - // If disposing equals false, the method has been called by the - // runtime from inside the finalizer and you should not reference - // other objects. Only unmanaged resources can be disposed. - - try - { - //Make sure Dispose does not get called more than once, by checking the disposed field - if(!_isDisposed && disposing) - { - AfterAll(); - } - _isDisposed = true; - } - finally - { - } + await AfterAllAsync(); } } } diff --git a/src/core/Akka.Cluster.Tests/ActorRefIgnoreSerializationSpec.cs b/src/core/Akka.Cluster.Tests/ActorRefIgnoreSerializationSpec.cs index 00a96334e41..c491a82d5d8 100644 --- a/src/core/Akka.Cluster.Tests/ActorRefIgnoreSerializationSpec.cs +++ b/src/core/Akka.Cluster.Tests/ActorRefIgnoreSerializationSpec.cs @@ -42,12 +42,11 @@ public ActorRefIgnoreSerializationSpec(ITestOutputHelper output) system2 = ActorSystem.Create("sys2", Config); } - - protected override void AfterAll() + protected override async Task AfterAllAsync() { - base.AfterAll(); - system1.Terminate(); - system2.Terminate(); + await base.AfterAllAsync(); + await ShutdownAsync(system1); + await ShutdownAsync(system2); } [Fact] diff --git a/src/core/Akka.Cluster.Tests/ShutdownAfterJoinSeedNodesSpec.cs b/src/core/Akka.Cluster.Tests/ShutdownAfterJoinSeedNodesSpec.cs index 059ea344ad2..57f014aea75 100644 --- a/src/core/Akka.Cluster.Tests/ShutdownAfterJoinSeedNodesSpec.cs +++ b/src/core/Akka.Cluster.Tests/ShutdownAfterJoinSeedNodesSpec.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Immutable; +using System.Threading.Tasks; using Akka.Actor; using Akka.Configuration; using Akka.TestKit; @@ -37,12 +38,12 @@ public ShutdownAfterJoinSeedNodesSpec() : base(Config) _ordinary1 = ActorSystem.Create(Sys.Name, Sys.Settings.Config); } - protected override void AfterTermination() + protected override async Task AfterAllAsync() { - base.AfterTermination(); - Shutdown(_seed1); - Shutdown(_seed2); - Shutdown(_ordinary1); + await base.AfterAllAsync(); + await ShutdownAsync(_seed1); + await ShutdownAsync(_seed2); + await ShutdownAsync(_ordinary1); } [Fact] diff --git a/src/core/Akka.Persistence.TCK/Query/CurrentEventsByPersistenceIdSpec.cs b/src/core/Akka.Persistence.TCK/Query/CurrentEventsByPersistenceIdSpec.cs index 8bc2b99644c..be2be21af18 100644 --- a/src/core/Akka.Persistence.TCK/Query/CurrentEventsByPersistenceIdSpec.cs +++ b/src/core/Akka.Persistence.TCK/Query/CurrentEventsByPersistenceIdSpec.cs @@ -6,6 +6,7 @@ //----------------------------------------------------------------------- using System; +using System.Threading.Tasks; using Akka.Actor; using Akka.Configuration; using Akka.Persistence.Query; @@ -203,10 +204,10 @@ private IActorRef SetupEmpty(string persistenceId) return Sys.ActorOf(Query.TestActor.Props(persistenceId)); } - protected override void Dispose(bool disposing) + public override Task DisposeAsync() { Materializer.Dispose(); - base.Dispose(disposing); + return base.DisposeAsync(); } } } diff --git a/src/core/Akka.Persistence.TCK/Query/CurrentPersistenceIdsSpec.cs b/src/core/Akka.Persistence.TCK/Query/CurrentPersistenceIdsSpec.cs index 68d2a75772f..f27dff07e5b 100644 --- a/src/core/Akka.Persistence.TCK/Query/CurrentPersistenceIdsSpec.cs +++ b/src/core/Akka.Persistence.TCK/Query/CurrentPersistenceIdsSpec.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Akka.Actor; using Akka.Configuration; using Akka.Persistence.Query; @@ -105,10 +106,10 @@ private IActorRef Setup(string persistenceId, int n) return pref; } - protected override void Dispose(bool disposing) + public override Task DisposeAsync() { Materializer.Dispose(); - base.Dispose(disposing); + return base.DisposeAsync(); } } } diff --git a/src/core/Akka.Persistence.TCK/Query/EventsByPersistenceIdSpec.cs b/src/core/Akka.Persistence.TCK/Query/EventsByPersistenceIdSpec.cs index 271e7512c61..2b5d12347b3 100644 --- a/src/core/Akka.Persistence.TCK/Query/EventsByPersistenceIdSpec.cs +++ b/src/core/Akka.Persistence.TCK/Query/EventsByPersistenceIdSpec.cs @@ -6,6 +6,7 @@ //----------------------------------------------------------------------- using System; +using System.Threading.Tasks; using Akka.Actor; using Akka.Configuration; using Akka.Persistence.Query; @@ -126,10 +127,10 @@ private IActorRef SetupEmpty(string persistenceId) return Sys.ActorOf(Query.TestActor.Props(persistenceId)); } - protected override void Dispose(bool disposing) + public override Task DisposeAsync() { Materializer.Dispose(); - base.Dispose(disposing); + return base.DisposeAsync(); } } } diff --git a/src/core/Akka.Persistence.TCK/Query/PersistenceIdsSpec.cs b/src/core/Akka.Persistence.TCK/Query/PersistenceIdsSpec.cs index 0a16b1099a8..8a7d9221a71 100644 --- a/src/core/Akka.Persistence.TCK/Query/PersistenceIdsSpec.cs +++ b/src/core/Akka.Persistence.TCK/Query/PersistenceIdsSpec.cs @@ -247,11 +247,10 @@ protected IActorRef WriteSnapshot(string persistenceId, int n) return pref; } - - protected override void Dispose(bool disposing) + public override Task DisposeAsync() { Materializer.Dispose(); - base.Dispose(disposing); + return base.DisposeAsync(); } } } diff --git a/src/core/Akka.Persistence.Tests/PersistenceSpec.cs b/src/core/Akka.Persistence.Tests/PersistenceSpec.cs index 5c37b941b36..0a21d5cea8a 100644 --- a/src/core/Akka.Persistence.Tests/PersistenceSpec.cs +++ b/src/core/Akka.Persistence.Tests/PersistenceSpec.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading.Tasks; using Akka.Configuration; using Akka.TestKit; using Akka.Util.Internal; @@ -61,9 +62,9 @@ protected PersistenceSpec(Config config = null, ITestOutputHelper output = null) public string NamePrefix { get { return Sys.Name; } } public string Name { get { return _name; } } - protected override void AfterAll() + protected override async Task AfterAllAsync() { - base.AfterAll(); + await base.AfterAllAsync(); Clean.Dispose(); } diff --git a/src/core/Akka.Persistence.Tests/Serialization/MessageSerializerRemotingSpec.cs b/src/core/Akka.Persistence.Tests/Serialization/MessageSerializerRemotingSpec.cs index 3cccbee62fc..9a41bda627e 100644 --- a/src/core/Akka.Persistence.Tests/Serialization/MessageSerializerRemotingSpec.cs +++ b/src/core/Akka.Persistence.Tests/Serialization/MessageSerializerRemotingSpec.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading.Tasks; using Akka.Actor; using Akka.Configuration; using Akka.TestKit; @@ -176,10 +177,10 @@ private Address Address(ActorSystem system) return ((ExtendedActorSystem) system).Provider.DefaultAddress; } - protected override void AfterTermination() + protected override async Task AfterAllAsync() { - _remoteSystem.Terminate().Wait(TimeSpan.FromSeconds(2)); - base.AfterTermination(); + await base.AfterAllAsync(); + await ShutdownAsync(_remoteSystem); } [Fact] diff --git a/src/core/Akka.Persistence.Tests/SnapshotDirectoryFailureSpec.cs b/src/core/Akka.Persistence.Tests/SnapshotDirectoryFailureSpec.cs index 209a96ec247..fea14a3b2bd 100644 --- a/src/core/Akka.Persistence.Tests/SnapshotDirectoryFailureSpec.cs +++ b/src/core/Akka.Persistence.Tests/SnapshotDirectoryFailureSpec.cs @@ -6,6 +6,7 @@ //----------------------------------------------------------------------- using System.IO; +using System.Threading.Tasks; using Akka.Actor; using Xunit; @@ -66,10 +67,10 @@ protected override void AtStartup() using (_file.Create()) {} } - protected override void AfterTermination() + protected override async Task AfterTerminationAsync() { _file.Delete(); - base.AfterTermination(); + await base.AfterTerminationAsync(); } [Fact] diff --git a/src/core/Akka.Remote.Tests/RemoteDeathWatchSpec.cs b/src/core/Akka.Remote.Tests/RemoteDeathWatchSpec.cs index ce2ae48062e..2bc9173f598 100644 --- a/src/core/Akka.Remote.Tests/RemoteDeathWatchSpec.cs +++ b/src/core/Akka.Remote.Tests/RemoteDeathWatchSpec.cs @@ -7,6 +7,7 @@ using System; using System.Text.RegularExpressions; +using System.Threading.Tasks; using Akka.Actor; using Akka.Actor.Dsl; using Akka.Configuration; @@ -44,15 +45,17 @@ public RemoteDeathWatchSpec() : base(_config) ConfigurationFactory.ParseString(@"akka.remote.dot-netty.tcp.port=2666").WithFallback(_config)); } - protected override void BeforeTermination() + protected override Task BeforeTerminationAsync() { var mute = EventFilter.Warning(pattern: new Regex("received dead letter.*Disassociate")).Mute(); Sys.EventStream.Publish(mute); + return Task.CompletedTask; } - protected override void AfterTermination() + protected override async Task AfterAllAsync() { - _other.Terminate().Wait(TimeSpan.FromSeconds(20)); + await base.AfterAllAsync(); + await ShutdownAsync(_other, verifySystemShutdown: true); } [Fact] diff --git a/src/core/Akka.Remote.Tests/RemoteMetricsSpec.cs b/src/core/Akka.Remote.Tests/RemoteMetricsSpec.cs index 9dfaf4d037c..0d9915c8e0a 100644 --- a/src/core/Akka.Remote.Tests/RemoteMetricsSpec.cs +++ b/src/core/Akka.Remote.Tests/RemoteMetricsSpec.cs @@ -7,6 +7,7 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Akka.Actor; using Akka.Configuration; using Akka.Event; @@ -50,10 +51,9 @@ public RemoteMetricsSpec(ITestOutputHelper output) Sys.EventStream.Subscribe(listener, typeof (Info)); } - - protected override void AfterTermination() + protected override async Task AfterTerminationAsync() { - Shutdown(_client); + await ShutdownAsync(_client); } diff --git a/src/core/Akka.Remote.Tests/RemoteRouterSpec.cs b/src/core/Akka.Remote.Tests/RemoteRouterSpec.cs index 90fa634f46a..c724126af44 100644 --- a/src/core/Akka.Remote.Tests/RemoteRouterSpec.cs +++ b/src/core/Akka.Remote.Tests/RemoteRouterSpec.cs @@ -132,9 +132,9 @@ public RemoteRouterSpec(ITestOutputHelper output) .Replace("${port}", port.ToString())); } - protected override void AfterTermination() + protected override async Task AfterTerminationAsync() { - Shutdown(masterSystem); + await ShutdownAsync(masterSystem); } private IEnumerable CollectRouteePaths(TestProbe probe, IActorRef router, int n) diff --git a/src/core/Akka.Remote.Tests/RemoteWatcherSpec.cs b/src/core/Akka.Remote.Tests/RemoteWatcherSpec.cs index 2c1ed3fc5f4..ef93ca5c304 100644 --- a/src/core/Akka.Remote.Tests/RemoteWatcherSpec.cs +++ b/src/core/Akka.Remote.Tests/RemoteWatcherSpec.cs @@ -6,6 +6,7 @@ //----------------------------------------------------------------------- using System; +using System.Threading.Tasks; using Akka.Actor; using Akka.TestKit; using Akka.Util.Internal; @@ -185,11 +186,12 @@ public RemoteWatcherSpec(ITestOutputHelper output) _heartbeatRspB = new RemoteWatcher.HeartbeatRsp(remoteAddressUid); } - protected override void AfterAll() + protected override async Task AfterAllAsync() { - Shutdown(_remoteSystem); - base.AfterAll(); + await ShutdownAsync(_remoteSystem); + await base.AfterAllAsync(); } + readonly ActorSystem _remoteSystem; readonly Address _remoteAddress; readonly RemoteWatcher.HeartbeatRsp _heartbeatRspB; diff --git a/src/core/Akka.Remote.Tests/RemotingSpec.cs b/src/core/Akka.Remote.Tests/RemotingSpec.cs index 5c36790f4fa..1f08f310b02 100644 --- a/src/core/Akka.Remote.Tests/RemotingSpec.cs +++ b/src/core/Akka.Remote.Tests/RemotingSpec.cs @@ -148,12 +148,11 @@ protected string GetOtherRemoteSysConfig() private TimeSpan DefaultTimeout => Dilated(TestKitSettings.DefaultTimeout); - - protected override void AfterAll() + protected override async Task AfterAllAsync() { - Shutdown(_remoteSystem, RemainingOrDefault); + await ShutdownAsync(_remoteSystem); AssociationRegistry.Clear(); - base.AfterAll(); + await base.AfterAllAsync(); } diff --git a/src/core/Akka.Remote.Tests/Serialization/SerializationTransportInformationSpec.cs b/src/core/Akka.Remote.Tests/Serialization/SerializationTransportInformationSpec.cs index ad786f096cf..64b68e490f5 100644 --- a/src/core/Akka.Remote.Tests/Serialization/SerializationTransportInformationSpec.cs +++ b/src/core/Akka.Remote.Tests/Serialization/SerializationTransportInformationSpec.cs @@ -179,10 +179,10 @@ public void Serialization_of_ActorRef_in_remote_message_must_resolve_Address() ExpectMsg(echo); } - protected override void AfterAll() + protected override async Task AfterAllAsync() { - base.AfterAll(); - Shutdown(System2, verifySystemShutdown: true); + await ShutdownAsync(System2, verifySystemShutdown: true); + await base.AfterAllAsync(); } } diff --git a/src/core/Akka.Remote.Tests/TransientSerializationErrorSpec.cs b/src/core/Akka.Remote.Tests/TransientSerializationErrorSpec.cs index 3cf5b868fc5..b151f8e3b45 100644 --- a/src/core/Akka.Remote.Tests/TransientSerializationErrorSpec.cs +++ b/src/core/Akka.Remote.Tests/TransientSerializationErrorSpec.cs @@ -12,6 +12,7 @@ using Xunit; using Akka.Serialization; using System.Runtime.Serialization; +using System.Threading.Tasks; namespace Akka.Remote.Tests { @@ -167,9 +168,9 @@ private static string GetConfig() "; } - protected override void AfterTermination() + protected override async Task AfterTerminationAsync() { - Shutdown(system2); + await ShutdownAsync(system2); } diff --git a/src/core/Akka.Remote.Tests/Transport/AkkaProtocolStressTest.cs b/src/core/Akka.Remote.Tests/Transport/AkkaProtocolStressTest.cs index ace0cd656d1..1de9da8de90 100644 --- a/src/core/Akka.Remote.Tests/Transport/AkkaProtocolStressTest.cs +++ b/src/core/Akka.Remote.Tests/Transport/AkkaProtocolStressTest.cs @@ -7,6 +7,7 @@ using System; using System.Text.RegularExpressions; +using System.Threading.Tasks; using Akka.Actor; using Akka.Configuration; using Akka.Remote.Transport; @@ -209,20 +210,21 @@ public void AkkaProtocolTransport_must_guarantee_at_most_once_delivery_and_messa #region Cleanup - protected override void BeforeTermination() + protected override async Task BeforeTerminationAsync() { EventFilter.Warning(start: "received dead letter").Mute(); EventFilter.Warning(new Regex("received dead letter.*(InboundPayload|Disassociate)")).Mute(); systemB.EventStream.Publish(new Mute(new WarningFilter(new RegexMatcher(new Regex("received dead letter.*(InboundPayload|Disassociate)"))), new ErrorFilter(typeof(EndpointException)), new ErrorFilter(new StartsWithString("AssociationError")))); - base.BeforeTermination(); + + await base.BeforeTerminationAsync(); } - protected override void AfterTermination() + protected override async Task AfterTerminationAsync() { - Shutdown(systemB); - base.AfterTermination(); + await ShutdownAsync(systemB); + await base.AfterTerminationAsync(); } #endregion diff --git a/src/core/Akka.Remote.Tests/Transport/DotNettySslSupportSpec.cs b/src/core/Akka.Remote.Tests/Transport/DotNettySslSupportSpec.cs index 8375caa452f..d07d1d7ac12 100644 --- a/src/core/Akka.Remote.Tests/Transport/DotNettySslSupportSpec.cs +++ b/src/core/Akka.Remote.Tests/Transport/DotNettySslSupportSpec.cs @@ -7,6 +7,7 @@ using System; using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; using Akka.Actor; using Akka.Configuration; using Akka.TestKit; @@ -180,15 +181,10 @@ public void Secure_transport_should_NOT_be_possible_between_systems_using_SSL_an #region helper classes / methods - - protected override void Dispose(bool disposing) + protected override async Task AfterAllAsync() { - base.Dispose(disposing); - if (disposing) - { - Shutdown(sys2, TimeSpan.FromSeconds(3)); - } - + await ShutdownAsync(sys2, TimeSpan.FromSeconds(3)); + await base.AfterAllAsync(); } private void InstallCert() diff --git a/src/core/Akka.Remote.Tests/Transport/ThrottlerTransportAdapterSpec.cs b/src/core/Akka.Remote.Tests/Transport/ThrottlerTransportAdapterSpec.cs index 01e6507402d..c8cd4be9a71 100644 --- a/src/core/Akka.Remote.Tests/Transport/ThrottlerTransportAdapterSpec.cs +++ b/src/core/Akka.Remote.Tests/Transport/ThrottlerTransportAdapterSpec.cs @@ -261,20 +261,20 @@ await Awaiting(async () => #region Cleanup - protected override void BeforeTermination() + protected override async Task BeforeTerminationAsync() { EventFilter.Warning(start: "received dead letter").Mute(); EventFilter.Warning(new Regex("received dead letter.*(InboundPayload|Disassociate)")).Mute(); _systemB.EventStream.Publish(new Mute(new WarningFilter(new RegexMatcher(new Regex("received dead letter.*(InboundPayload|Disassociate)"))), new ErrorFilter(typeof(EndpointException)), new ErrorFilter(new StartsWithString("AssociationError")))); - base.BeforeTermination(); + await base.BeforeTerminationAsync(); } - protected override void AfterTermination() + protected override async Task AfterTerminationAsync() { - Shutdown(_systemB); - base.AfterTermination(); + await ShutdownAsync(_systemB); + await base.AfterTerminationAsync(); } #endregion diff --git a/src/core/Akka.Remote.Tests/UntrustedSpec.cs b/src/core/Akka.Remote.Tests/UntrustedSpec.cs index 1b81b1175fa..f32a5785dd8 100644 --- a/src/core/Akka.Remote.Tests/UntrustedSpec.cs +++ b/src/core/Akka.Remote.Tests/UntrustedSpec.cs @@ -6,6 +6,7 @@ //----------------------------------------------------------------------- using System; +using System.Threading.Tasks; using Akka.Actor; using Akka.Configuration; using Akka.Event; @@ -71,9 +72,9 @@ public UntrustedSpec(ITestOutputHelper output) } - protected override void AfterTermination() + protected override async Task AfterTerminationAsync() { - Shutdown(_client); + await ShutdownAsync(_client); } diff --git a/src/core/Akka.Streams.Tests/Dsl/StreamRefsSerializerSpec.cs b/src/core/Akka.Streams.Tests/Dsl/StreamRefsSerializerSpec.cs index f1984aa758e..a35e496fa98 100644 --- a/src/core/Akka.Streams.Tests/Dsl/StreamRefsSerializerSpec.cs +++ b/src/core/Akka.Streams.Tests/Dsl/StreamRefsSerializerSpec.cs @@ -7,6 +7,7 @@ using System; using System.Linq; +using System.Threading.Tasks; using Akka.Actor; using Akka.Actor.Internal; using Akka.Configuration; @@ -169,13 +170,18 @@ protected StreamRefsSerializerSpec(Config config, ITestOutputHelper output = nul private readonly TestProbe _probe; private readonly IActorRef _remoteActor; - protected override void BeforeTermination() + protected override async Task BeforeTerminationAsync() { - base.BeforeTermination(); - RemoteSystem.Dispose(); + await base.BeforeTerminationAsync(); Materializer.Dispose(); } + protected override async Task AfterAllAsync() + { + await base.AfterAllAsync(); + await ShutdownAsync(RemoteSystem); + } + [Fact] public void source_ref_must_be_correctly_sent_over_wire_even_if_enveloped_in_poco() { diff --git a/src/core/Akka.Streams.Tests/Dsl/StreamRefsSpec.cs b/src/core/Akka.Streams.Tests/Dsl/StreamRefsSpec.cs index 9c912d86c30..1daa6fe2961 100644 --- a/src/core/Akka.Streams.Tests/Dsl/StreamRefsSpec.cs +++ b/src/core/Akka.Streams.Tests/Dsl/StreamRefsSpec.cs @@ -16,6 +16,7 @@ using System; using System.Linq; using System.Threading; +using System.Threading.Tasks; using FluentAssertions.Extensions; using Xunit; using Xunit.Abstractions; @@ -222,13 +223,18 @@ protected StreamRefsSpec(Config config, ITestOutputHelper output = null) : base( private readonly TestProbe _probe; private readonly IActorRef _remoteActor; - protected override void BeforeTermination() + protected override async Task BeforeTerminationAsync() { - base.BeforeTermination(); - RemoteSystem.Dispose(); + await base.BeforeTerminationAsync(); Materializer.Dispose(); } + protected override async Task AfterAllAsync() + { + await base.AfterAllAsync(); + await ShutdownAsync(RemoteSystem); + } + [Fact] public void SourceRef_must_send_messages_via_remoting() { diff --git a/src/core/Akka.Streams.Tests/Dsl/UnfoldResourceSourceSpec.cs b/src/core/Akka.Streams.Tests/Dsl/UnfoldResourceSourceSpec.cs index 7615a63a062..96f93c54e30 100644 --- a/src/core/Akka.Streams.Tests/Dsl/UnfoldResourceSourceSpec.cs +++ b/src/core/Akka.Streams.Tests/Dsl/UnfoldResourceSourceSpec.cs @@ -9,6 +9,7 @@ using System; using System.IO; using System.Linq; +using System.Threading.Tasks; using Akka.Actor; using Akka.IO; using Akka.Streams.Dsl; @@ -308,9 +309,9 @@ public void A_UnfoldResourceSource_must_not_close_the_resource_twice_when_read_f closedCounter.Current.Should().Be(1); } - protected override void AfterAll() + protected override async Task AfterAllAsync() { - base.AfterAll(); + await base.AfterAllAsync(); _manyLinesFile.Delete(); } } diff --git a/src/core/Akka.Streams.Tests/IO/FileSourceSpec.cs b/src/core/Akka.Streams.Tests/IO/FileSourceSpec.cs index 7f4a101b6fc..8270c1324d7 100644 --- a/src/core/Akka.Streams.Tests/IO/FileSourceSpec.cs +++ b/src/core/Akka.Streams.Tests/IO/FileSourceSpec.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Text; using System.Threading; +using System.Threading.Tasks; using Akka.Actor; using Akka.IO; using Akka.Streams.Dsl; @@ -364,14 +365,15 @@ private FileInfo NotExistingFile() return f; } - protected override void AfterAll() + protected override async Task AfterAllAsync() { - base.AfterAll(); - + await base.AfterAllAsync(); + //give the system enough time to shutdown and release the file handle - Thread.Sleep(500); + await Task.Delay(500); _manyLinesPath?.Delete(); _testFilePath?.Delete(); } + } } diff --git a/src/core/Akka.TestKit.Tests/TestActorRefTests/BossActor.cs b/src/core/Akka.TestKit.Tests/TestActorRefTests/BossActor.cs index e16fc5a5578..825028434d0 100644 --- a/src/core/Akka.TestKit.Tests/TestActorRefTests/BossActor.cs +++ b/src/core/Akka.TestKit.Tests/TestActorRefTests/BossActor.cs @@ -6,7 +6,10 @@ //----------------------------------------------------------------------- using System; +using System.Threading; using Akka.Actor; +using Akka.Util; +using Akka.Util.Internal; namespace Akka.TestKit.Tests.TestActorRefTests { @@ -14,9 +17,9 @@ public class BossActor : TActorBase { private TestActorRef _child; - public BossActor() + public BossActor(AtomicCounter counter, Thread parentThread, AtomicReference otherThread) : base(parentThread, otherThread) { - _child = new TestActorRef(Context.System, Props.Create(), Self, "child"); + _child = new TestActorRef(Context.System, Props.Create(() => new InternalActor(counter, parentThread, otherThread)), Self, "child"); } protected override SupervisorStrategy SupervisorStrategy() @@ -36,14 +39,21 @@ protected override bool ReceiveMessage(object message) private class InternalActor : TActorBase { + private readonly AtomicCounter _counter; + + public InternalActor(AtomicCounter counter, Thread parentThread, AtomicReference otherThread) : base(parentThread, otherThread) + { + _counter = counter; + } + protected override void PreRestart(Exception reason, object message) { - TestActorRefSpec.Counter--; + _counter.Decrement(); } protected override void PostRestart(Exception reason) { - TestActorRefSpec.Counter--; + _counter.Decrement(); } protected override bool ReceiveMessage(object message) diff --git a/src/core/Akka.TestKit.Tests/TestActorRefTests/ReplyActor.cs b/src/core/Akka.TestKit.Tests/TestActorRefTests/ReplyActor.cs index 58106f4950a..1d4080c6352 100644 --- a/src/core/Akka.TestKit.Tests/TestActorRefTests/ReplyActor.cs +++ b/src/core/Akka.TestKit.Tests/TestActorRefTests/ReplyActor.cs @@ -5,7 +5,9 @@ // //----------------------------------------------------------------------- +using System.Threading; using Akka.Actor; +using Akka.Util; namespace Akka.TestKit.Tests.TestActorRefTests { @@ -15,16 +17,15 @@ public class ReplyActor : TActorBase protected override bool ReceiveMessage(object message) { - var strMessage = message as string; - switch(strMessage) + switch((string)message) { case "complexRequest": _replyTo = Sender; - var worker = new TestActorRef(System, Props.Create()); + var worker = new TestActorRef(System, Props.Create(() => new WorkerActor(ParentThread, OtherThread))); worker.Tell("work"); return true; case "complexRequest2": - var worker2 = new TestActorRef(System, Props.Create()); + var worker2 = new TestActorRef(System, Props.Create(() => new WorkerActor(ParentThread, OtherThread))); worker2.Tell(Sender, Self); return true; case "workDone": @@ -36,6 +37,10 @@ protected override bool ReceiveMessage(object message) } return false; } + + public ReplyActor(Thread parentThread, AtomicReference otherThread) : base(parentThread, otherThread) + { + } } } diff --git a/src/core/Akka.TestKit.Tests/TestActorRefTests/SenderActor.cs b/src/core/Akka.TestKit.Tests/TestActorRefTests/SenderActor.cs index 0abce8adf84..2b4f23b0e28 100644 --- a/src/core/Akka.TestKit.Tests/TestActorRefTests/SenderActor.cs +++ b/src/core/Akka.TestKit.Tests/TestActorRefTests/SenderActor.cs @@ -5,17 +5,22 @@ // //----------------------------------------------------------------------- +using System.Threading; using Akka.Actor; +using Akka.Util; +using Akka.Util.Internal; namespace Akka.TestKit.Tests.TestActorRefTests { public class SenderActor : TActorBase { + private readonly AtomicCounter _counter; private readonly IActorRef _replyActor; - public SenderActor(IActorRef replyActor) + public SenderActor(IActorRef replyActor, AtomicCounter counter, Thread parentThread, AtomicReference otherThread) : base(parentThread, otherThread) { _replyActor = replyActor; + _counter = counter; } protected override bool ReceiveMessage(object message) @@ -33,10 +38,10 @@ protected override bool ReceiveMessage(object message) _replyActor.Tell("simpleRequest", Self); return true; case "complexReply": - TestActorRefSpec.Counter--; + _counter.Decrement(); return true; case "simpleReply": - TestActorRefSpec.Counter--; + _counter.Decrement(); return true; } return false; diff --git a/src/core/Akka.TestKit.Tests/TestActorRefTests/TActorBase.cs b/src/core/Akka.TestKit.Tests/TestActorRefTests/TActorBase.cs index f4c9d83e168..ade5b65b844 100644 --- a/src/core/Akka.TestKit.Tests/TestActorRefTests/TActorBase.cs +++ b/src/core/Akka.TestKit.Tests/TestActorRefTests/TActorBase.cs @@ -7,17 +7,27 @@ using System.Threading; using Akka.Actor; +using Akka.Util; namespace Akka.TestKit.Tests.TestActorRefTests { // ReSharper disable once InconsistentNaming public abstract class TActorBase : ActorBase { + protected readonly Thread ParentThread; + protected readonly AtomicReference OtherThread; + + protected TActorBase(Thread parentThread, AtomicReference otherThread) + { + ParentThread = parentThread; + OtherThread = otherThread; + } + protected sealed override bool Receive(object message) { var currentThread = Thread.CurrentThread; - if(currentThread != TestActorRefSpec.Thread) - TestActorRefSpec.OtherThread = currentThread; + if (currentThread != ParentThread) + OtherThread.GetAndSet(currentThread); return ReceiveMessage(message); } diff --git a/src/core/Akka.TestKit.Tests/TestActorRefTests/TestActorRefSpec.cs b/src/core/Akka.TestKit.Tests/TestActorRefTests/TestActorRefSpec.cs index c6a331708a5..4e8c2c9fb40 100644 --- a/src/core/Akka.TestKit.Tests/TestActorRefTests/TestActorRefSpec.cs +++ b/src/core/Akka.TestKit.Tests/TestActorRefTests/TestActorRefSpec.cs @@ -11,21 +11,21 @@ using Akka.Configuration; using Akka.Dispatch; using Akka.TestKit.Internal; +using Akka.Util; +using Akka.Util.Internal; using Xunit; namespace Akka.TestKit.Tests.TestActorRefTests { public class TestActorRefSpec : AkkaSpec { - public static int Counter = 4; - public static readonly Thread Thread = Thread.CurrentThread; - public static Thread OtherThread; - + private readonly AtomicCounter _counter = new AtomicCounter(4); + private readonly Thread _thread = Thread.CurrentThread; + private readonly AtomicReference _otherThread = new AtomicReference(null); public TestActorRefSpec() : base(GetConfig()) { - OtherThread = null; } private TimeSpan DefaultTimeout { get { return Dilated(TestKitSettings.DefaultTimeout); } } @@ -37,7 +37,7 @@ private static Config GetConfig() private void AssertThread() { - Assert.True(OtherThread == null || OtherThread == Thread, "Thread"); + Assert.True(_otherThread.Value == null || _otherThread.Value == _thread, "Thread"); } [Fact] @@ -79,22 +79,24 @@ public void TestActorRef_must_support_nested_Actor_creation_when_used_with_Actor [Fact] public void TestActorRef_must_support_reply_via_sender() { - var serverRef = new TestActorRef(Sys, Props.Create()); - var clientRef = new TestActorRef(Sys, Props.Create(() => new SenderActor(serverRef))); + var serverRef = new TestActorRef(Sys, Props.Create(() => + new ReplyActor(_thread, _otherThread))); + var clientRef = new TestActorRef(Sys, Props.Create(() => + new SenderActor(serverRef, _counter, _thread, _otherThread))); - Counter = 4; + _counter.GetAndSet(4); clientRef.Tell("complex"); clientRef.Tell("simple"); clientRef.Tell("simple"); clientRef.Tell("simple"); - Counter.ShouldBe(0); + _counter.Current.ShouldBe(0); - Counter = 4; + _counter.GetAndSet(4); clientRef.Tell("complex2"); clientRef.Tell("simple"); clientRef.Tell("simple"); clientRef.Tell("simple"); - Counter.ShouldBe(0); + _counter.Current.ShouldBe(0); AssertThread(); } @@ -103,7 +105,7 @@ public void TestActorRef_must_support_reply_via_sender() public void TestActorRef_must_stop_when_sent_a_PoisonPill() { //TODO: Should have this surrounding all code EventFilter[ActorKilledException]() intercept { - var a = new TestActorRef(Sys, Props.Create(), null, "will-be-killed"); + var a = new TestActorRef(Sys, Props.Create(() => new WorkerActor(_thread, _otherThread)), null, "will-be-killed"); Sys.ActorOf(Props.Create(() => new WatchAndForwardActor(a, TestActor)), "forwarder"); a.Tell(PoisonPill.Instance); ExpectMsg(w => w.Terminated.ActorRef == a, TimeSpan.FromSeconds(10), string.Format("that the terminated actor was the one killed, i.e. {0}", a.Path)); @@ -116,18 +118,18 @@ public void TestActorRef_must_stop_when_sent_a_PoisonPill() public void TestActorRef_must_restart_when_killed() { //TODO: Should have this surrounding all code EventFilter[ActorKilledException]() intercept { - Counter = 2; - var boss = new TestActorRef(Sys, Props.Create()); + _counter.GetAndSet(2); + var boss = new TestActorRef(Sys, Props.Create(() => new BossActor(_counter, _thread, _otherThread))); boss.Tell("sendKill"); - Assert.Equal(0, Counter); + Assert.Equal(0, _counter.Current); AssertThread(); } [Fact] public void TestActorRef_must_support_futures() { - var worker = new TestActorRef(Sys, Props.Create()); + var worker = new TestActorRef(Sys, Props.Create(() => new WorkerActor(_thread, _otherThread))); var task = worker.Ask("work"); Assert.True(task.IsCompleted, "Task should be completed"); if(!task.Wait(DefaultTimeout)) XAssert.Fail("Timed out"); //Using a timeout to stop the test if there is something wrong with the code @@ -137,7 +139,7 @@ public void TestActorRef_must_support_futures() [Fact] public void TestActorRef_must_allow_access_to_internals() { - var actorRef = new TestActorRef(Sys, Props.Create()); + var actorRef = new TestActorRef(Sys, Props.Create(() => new SaveStringActor(_thread, _otherThread))); actorRef.Tell("Hejsan!"); var actor = actorRef.UnderlyingActor; Assert.Equal("Hejsan!", actor.ReceivedString); @@ -146,14 +148,14 @@ public void TestActorRef_must_allow_access_to_internals() [Fact] public void TestActorRef_must_set_ReceiveTimeout_to_None() { - var a = new TestActorRef(Sys, Props.Create()); + var a = new TestActorRef(Sys, Props.Create(() => new WorkerActor(_thread, _otherThread))); ((IInternalActor)a.UnderlyingActor).ActorContext.ReceiveTimeout.ShouldBe(null); } [Fact] public void TestActorRef_must_set_CallingThreadDispatcher() { - var a = new TestActorRef(Sys, Props.Create()); + var a = new TestActorRef(Sys, Props.Create(() => new WorkerActor(_thread, _otherThread))); var actorRef = (InternalTestActorRef)a.Ref; Assert.IsType(actorRef.Cell.Dispatcher); } @@ -161,7 +163,7 @@ public void TestActorRef_must_set_CallingThreadDispatcher() [Fact] public void TestActorRef_must_allow_override_of_dispatcher() { - var a = new TestActorRef(Sys, Props.Create().WithDispatcher("test-dispatcher1")); + var a = new TestActorRef(Sys, Props.Create(() => new WorkerActor(_thread, _otherThread)).WithDispatcher("test-dispatcher1")); var actorRef = (InternalTestActorRef)a.Ref; Assert.IsType(actorRef.Cell.Dispatcher); } @@ -169,7 +171,7 @@ public void TestActorRef_must_allow_override_of_dispatcher() [Fact] public void TestActorRef_must_proxy_receive_for_the_underlying_actor_without_sender() { - var a = new TestActorRef(Sys, Props.Create()); + var a = new TestActorRef(Sys, Props.Create(() => new WorkerActor(_thread, _otherThread))); a.Receive("work"); var actorRef = (InternalTestActorRef)a.Ref; Assert.True(actorRef.IsTerminated); @@ -178,7 +180,7 @@ public void TestActorRef_must_proxy_receive_for_the_underlying_actor_without_sen [Fact] public void TestActorRef_must_proxy_receive_for_the_underlying_actor_with_sender() { - var a = new TestActorRef(Sys, Props.Create()); + var a = new TestActorRef(Sys, Props.Create(() => new WorkerActor(_thread, _otherThread))); a.Receive("work", TestActor); //This will stop the actor var actorRef = (InternalTestActorRef)a.Ref; Assert.True(actorRef.IsTerminated); @@ -220,6 +222,9 @@ protected override bool ReceiveMessage(object message) ReceivedString = message as string; return true; } + + public SaveStringActor(Thread parentThread, AtomicReference otherThread) : base(parentThread, otherThread) + { } } } } diff --git a/src/core/Akka.TestKit.Tests/TestActorRefTests/WorkerActor.cs b/src/core/Akka.TestKit.Tests/TestActorRefTests/WorkerActor.cs index 09dd91e6f1c..17f463aa388 100644 --- a/src/core/Akka.TestKit.Tests/TestActorRefTests/WorkerActor.cs +++ b/src/core/Akka.TestKit.Tests/TestActorRefTests/WorkerActor.cs @@ -5,12 +5,18 @@ // //----------------------------------------------------------------------- +using System.Threading; using Akka.Actor; +using Akka.Util; namespace Akka.TestKit.Tests.TestActorRefTests { public class WorkerActor : TActorBase { + public WorkerActor(Thread parentThread, AtomicReference otherThread) : base(parentThread, otherThread) + { + } + protected override bool ReceiveMessage(object message) { if((message as string) == "work") diff --git a/src/core/Akka.TestKit.Tests/TestEventListenerTests/EventFilterTestBase.cs b/src/core/Akka.TestKit.Tests/TestEventListenerTests/EventFilterTestBase.cs index c4131841eff..7700a5c9d21 100644 --- a/src/core/Akka.TestKit.Tests/TestEventListenerTests/EventFilterTestBase.cs +++ b/src/core/Akka.TestKit.Tests/TestEventListenerTests/EventFilterTestBase.cs @@ -5,6 +5,7 @@ // //----------------------------------------------------------------------- +using System.Threading.Tasks; using Akka.Event; using Akka.Testkit.Tests.TestEventListenerTests; @@ -31,14 +32,14 @@ protected EventFilterTestBase(string config) protected abstract void SendRawLogEventMessage(object message); - protected override void AfterAll() + protected override Task AfterAllAsync() { //After every test we make sure no uncatched messages have been logged if(TestSuccessful) { EnsureNoMoreLoggedMessages(); } - base.AfterAll(); + return base.AfterAllAsync(); } private void EnsureNoMoreLoggedMessages() diff --git a/src/core/Akka.TestKit/TestKitBase.cs b/src/core/Akka.TestKit/TestKitBase.cs index a3bf106516a..3045c42635f 100644 --- a/src/core/Akka.TestKit/TestKitBase.cs +++ b/src/core/Akka.TestKit/TestKitBase.cs @@ -495,6 +495,22 @@ public virtual void Shutdown( => ShutdownAsync(_testState.System, duration, verifySystemShutdown, cancellationToken) .ConfigureAwait(false).GetAwaiter().GetResult(); + /// + /// Shuts down this system. + /// On failure debug output will be logged about the remaining actors in the system. + /// If verifySystemShutdown is true, then an exception will be thrown on failure. + /// + /// Optional. The duration to wait for shutdown. Default is 5 seconds multiplied with the config value "akka.test.timefactor". + /// if set to true an exception will be thrown on failure. + /// to cancel the operation + /// TBD + public virtual async Task ShutdownAsync( + TimeSpan? duration = null, + bool verifySystemShutdown = false, + CancellationToken cancellationToken = default) + => await ShutdownAsync(_testState.System, duration, verifySystemShutdown, cancellationToken) + .ConfigureAwait(false); + /// /// Shuts down the specified system. /// On failure debug output will be logged about the remaining actors in the system. @@ -538,8 +554,8 @@ protected virtual async Task ShutdownAsync( { const string msg = "Failed to stop [{0}] within [{1}] \n{2}"; if(verifySystemShutdown) - throw new TimeoutException(string.Format(msg, system.Name, durationValue, "")); - system.Log.Warning(msg, system.Name, durationValue, ""); //TODO: replace "" with system.PrintTree() + throw new TimeoutException(string.Format(msg, system.Name, durationValue, ((ExtendedActorSystem) system).PrintTree())); + system.Log.Warning(msg, system.Name, durationValue, ((ExtendedActorSystem) system).PrintTree()); } } diff --git a/src/core/Akka.Tests.Shared.Internals/AkkaSpec.cs b/src/core/Akka.Tests.Shared.Internals/AkkaSpec.cs index b50088d8b11..f3d9476f5fc 100644 --- a/src/core/Akka.Tests.Shared.Internals/AkkaSpec.cs +++ b/src/core/Akka.Tests.Shared.Internals/AkkaSpec.cs @@ -86,29 +86,35 @@ private void BeforeAll() AtStartup(); } - protected override void AfterAll() + protected override async Task AfterAllAsync() { - BeforeTermination(); - base.AfterAll(); - AfterTermination(); + await BeforeTerminationAsync(); + await base.AfterAllAsync(); + await AfterTerminationAsync(); } protected virtual void AtStartup() { } - protected virtual void BeforeTermination() { } + protected virtual Task BeforeTerminationAsync() + { + return Task.CompletedTask; + } - protected virtual void AfterTermination() { } + protected virtual Task AfterTerminationAsync() + { + return Task.CompletedTask; + } private static string GetCallerName() { var systemNumber = Interlocked.Increment(ref _systemNumber); var stackTrace = new StackTrace(0); - var name = stackTrace.GetFrames(). - Select(f => f.GetMethod()). - Where(m => m.DeclaringType != null). - SkipWhile(m => m.DeclaringType.Name == "AkkaSpec"). - Select(m => _nameReplaceRegex.Replace(m.DeclaringType.Name + "-" + systemNumber, "-")). - FirstOrDefault() ?? "test"; + var name = stackTrace.GetFrames()? + .Select(f => f.GetMethod()) + .Where(m => m.DeclaringType != null) + .SkipWhile(m => m.DeclaringType.Name == "AkkaSpec") + .Select(m => _nameReplaceRegex.Replace(m.DeclaringType.Name + "-" + systemNumber, "-")) + .FirstOrDefault() ?? "test"; return name; }