From 1ca3cb15811936ec2f00000ba167fec48f954519 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Wed, 7 May 2025 05:22:43 +0700 Subject: [PATCH 01/11] Introduce CancellationToken to `WithCircuitBreaker` --- .../AsyncWriteProxyEx.cs | 55 +-- .../SnapshotStoreProxy.cs | 48 ++- .../Bugfix7399Specs.cs | 25 +- .../Utilities/CircuitBreakerDocSpec.cs | 2 +- .../Journal/TestJournal.cs | 8 +- .../SnapshotStore/TestSnapshotStore.cs | 22 +- .../Journal/ChaosJournal.cs | 7 +- .../Journal/SteppingMemoryJournal.cs | 13 +- .../PersistentActorDeleteFailureSpec.cs | 3 +- .../PersistentActorFailureSpec.cs | 5 +- .../SnapshotFailureRobustnessSpec.cs | 19 +- .../Akka.Persistence/Journal/AsyncRecovery.cs | 4 +- .../Journal/AsyncWriteJournal.cs | 106 +++--- .../Journal/AsyncWriteProxy.cs | 37 +- .../Akka.Persistence/Journal/MemoryJournal.cs | 7 +- .../Snapshot/LocalSnapshotStore.cs | 11 +- .../Snapshot/MemorySnapshotStore.cs | 22 +- .../Snapshot/NoSnapshotStore.cs | 36 +- .../Snapshot/SnapshotStore.cs | 346 +++++++++++------- .../Akka.Tests/Pattern/CircuitBreakerSpec.cs | 44 +-- .../Pattern/CircuitBreakerStressSpec.cs | 9 +- src/core/Akka/Pattern/CircuitBreaker.cs | 73 +++- src/core/Akka/Pattern/CircuitBreakerState.cs | 135 ++++++- src/core/Akka/Util/Internal/AtomicState.cs | 140 ++++++- .../Journal/SqliteJournal.cs | 18 +- .../Snapshot/SqliteSnapshotStore.cs | 19 +- 26 files changed, 799 insertions(+), 415 deletions(-) diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/AsyncWriteProxyEx.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/AsyncWriteProxyEx.cs index 3f0c2baffb3..c47098fa349 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/AsyncWriteProxyEx.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/AsyncWriteProxyEx.cs @@ -158,22 +158,14 @@ protected internal override bool AroundReceive(Receive receive, object message) - /// - /// TBD - /// - /// TBD - /// - /// This exception is thrown when the store has not been initialized. - /// - /// TBD - protected override Task> WriteMessagesAsync(IEnumerable messages) + protected override Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { var trueMsgs = messages.ToArray(); if (_store == null) return StoreNotInitialized>(); - return _store.Ask(sender => new WriteMessages(trueMsgs, sender, 1), Timeout, CancellationToken.None) + return _store.Ask(sender => new WriteMessages(trueMsgs, sender, 1), Timeout, cancellationToken) .ContinueWith(r => { if (r.IsCanceled) @@ -190,31 +182,23 @@ protected override Task> WriteMessagesAsync(IEnumerabl }, TaskContinuationOptions.ExecuteSynchronously); } - /// - /// TBD - /// - /// TBD - /// TBD - /// - /// This exception is thrown when the store has not been initialized. - /// - /// TBD - protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) + protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, CancellationToken cancellationToken) { if (_store == null) return StoreNotInitialized(); var result = new TaskCompletionSource(); - _store.Ask(sender => new DeleteMessagesTo(persistenceId, toSequenceNr, sender), Timeout, CancellationToken.None).ContinueWith(r => - { - if (r.IsFaulted) - result.TrySetException(r.Exception); - else if (r.IsCanceled) - result.TrySetException(new TimeoutException()); - else - result.TrySetResult(true); - }, TaskContinuationOptions.ExecuteSynchronously); + _store.Ask(sender => new DeleteMessagesTo(persistenceId, toSequenceNr, sender), Timeout, cancellationToken) + .ContinueWith(r => + { + if (r.IsFaulted) + result.TrySetException(r.Exception); + else if (r.IsCanceled) + result.TrySetException(new TimeoutException()); + else + result.TrySetResult(true); + }, TaskContinuationOptions.ExecuteSynchronously); return result.Task; } @@ -245,23 +229,14 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten return replayCompletionPromise.Task; } - /// - /// TBD - /// - /// TBD - /// TBD - /// - /// This exception is thrown when the store has not been initialized. - /// - /// TBD - public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) + public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken) { if (_store == null) return StoreNotInitialized(); var result = new TaskCompletionSource(); - _store.Ask(sender => new ReplayMessages(0, 0, 0, persistenceId, sender), Timeout, CancellationToken.None) + _store.Ask(sender => new ReplayMessages(0, 0, 0, persistenceId, sender), Timeout, cancellationToken) .ContinueWith(t => { if (t.IsFaulted) diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs index 74cf5972410..2c8a4d98d5f 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs @@ -7,6 +7,7 @@ using System; using System.Runtime.ExceptionServices; +using System.Threading; using System.Threading.Tasks; using Akka.Actor; using Akka.Event; @@ -89,14 +90,17 @@ protected internal override bool AroundReceive(Receive receive, object message) return true; } - protected async override Task DeleteAsync(SnapshotMetadata metadata) + protected override async Task DeleteAsync( + SnapshotMetadata metadata, + CancellationToken cancellationToken) { if (_store == null) - throw new TimeoutException("Store not intialized."); - var s = Sender; + throw new TimeoutException("Store not initialized."); try { - var response = await _store.Ask(new DeleteSnapshot(metadata), Timeout); + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(Timeout); + var response = await _store.Ask(new DeleteSnapshot(metadata), cts.Token); if (response is DeleteSnapshotFailure f) { ExceptionDispatchInfo.Capture(f.Cause).Throw(); @@ -108,14 +112,18 @@ protected async override Task DeleteAsync(SnapshotMetadata metadata) } } - protected async override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + protected override async Task DeleteAsync( + string persistenceId, + SnapshotSelectionCriteria criteria, + CancellationToken cancellationToken) { if (_store == null) - throw new TimeoutException("Store not intialized."); - var s = Sender; + throw new TimeoutException("Store not initialized."); try { - var response = await _store.Ask(new DeleteSnapshots(persistenceId, criteria), Timeout); + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(Timeout); + var response = await _store.Ask(new DeleteSnapshots(persistenceId, criteria), cts.Token); if (response is DeleteSnapshotsFailure f) { ExceptionDispatchInfo.Capture(f.Cause).Throw(); @@ -127,14 +135,18 @@ protected async override Task DeleteAsync(string persistenceId, SnapshotSelectio } } - protected override async Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) + protected override async Task LoadAsync( + string persistenceId, + SnapshotSelectionCriteria criteria, + CancellationToken cancellationToken) { if (_store == null) - throw new TimeoutException("Store not intialized."); - var s = Sender; + throw new TimeoutException("Store not initialized."); try { - var response = await _store.Ask(new LoadSnapshot(persistenceId, criteria, criteria.MaxSequenceNr), Timeout); + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(Timeout); + var response = await _store.Ask(new LoadSnapshot(persistenceId, criteria, criteria.MaxSequenceNr), cts.Token); switch (response) { case LoadSnapshotResult ls: @@ -154,14 +166,18 @@ protected override async Task LoadAsync(string persistenceId, throw new TimeoutException(); } - protected override async Task SaveAsync(SnapshotMetadata metadata, object snapshot) + protected override async Task SaveAsync( + SnapshotMetadata metadata, + object snapshot, + CancellationToken cancellationToken) { if (_store == null) - throw new TimeoutException("Store not intialized."); - var s = Sender; + throw new TimeoutException("Store not initialized."); try { - var response = await _store.Ask(new SaveSnapshot(metadata, snapshot), Timeout); + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(Timeout); + var response = await _store.Ask(new SaveSnapshot(metadata, snapshot), cts.Token); if (response is SaveSnapshotFailure f) { ExceptionDispatchInfo.Capture(f.Cause).Throw(); diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/Bugfix7399Specs.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/Bugfix7399Specs.cs index 4aff1715042..5c62adf13db 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/Bugfix7399Specs.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/Bugfix7399Specs.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Akka.Actor; using Akka.Configuration; @@ -150,14 +151,14 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten recoveryCallback); } - protected override Task> WriteMessagesAsync(IEnumerable messages) + protected override Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { if (!Working) { throw new ApplicationException("Failed"); } - return base.WriteMessagesAsync(messages); + return base.WriteMessagesAsync(messages, cancellationToken); } } @@ -165,7 +166,9 @@ public class FailingSnapshot : SnapshotStore { public static bool Working = false; - protected override Task DeleteAsync(SnapshotMetadata metadata) + protected override Task DeleteAsync( + SnapshotMetadata metadata, + CancellationToken cancellationToken) { if (!Working) { @@ -175,7 +178,10 @@ protected override Task DeleteAsync(SnapshotMetadata metadata) return Task.CompletedTask; } - protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + protected override Task DeleteAsync( + string persistenceId, + SnapshotSelectionCriteria criteria, + CancellationToken cancellationToken) { if (!Working) { @@ -185,8 +191,10 @@ protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCrite return Task.CompletedTask; } - protected override async Task LoadAsync(string persistenceId, - SnapshotSelectionCriteria criteria) + protected override async Task LoadAsync( + string persistenceId, + SnapshotSelectionCriteria criteria, + CancellationToken cancellationToken) { if (!Working) { @@ -196,7 +204,10 @@ protected override async Task LoadAsync(string persistenceId, return null; } - protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) + protected override Task SaveAsync( + SnapshotMetadata metadata, + object snapshot, + CancellationToken cancellationToken) { if (!Working) { diff --git a/src/core/Akka.Docs.Tests/Utilities/CircuitBreakerDocSpec.cs b/src/core/Akka.Docs.Tests/Utilities/CircuitBreakerDocSpec.cs index 18e3ac726d2..345e9c1efbf 100644 --- a/src/core/Akka.Docs.Tests/Utilities/CircuitBreakerDocSpec.cs +++ b/src/core/Akka.Docs.Tests/Utilities/CircuitBreakerDocSpec.cs @@ -52,7 +52,7 @@ public DangerousActorCallProtection() Receive(str => str.Equals("is my middle name"), _ => { var sender = this.Sender; - breaker.WithCircuitBreaker(() => Task.FromResult(dangerousCall)).PipeTo(sender); + breaker.WithCircuitBreaker(_ => Task.FromResult(dangerousCall)).PipeTo(sender); }); Receive(str => str.Equals("block for me"), _ => diff --git a/src/core/Akka.Persistence.TestKit/Journal/TestJournal.cs b/src/core/Akka.Persistence.TestKit/Journal/TestJournal.cs index aabdcb5c41e..bd7f66970a9 100644 --- a/src/core/Akka.Persistence.TestKit/Journal/TestJournal.cs +++ b/src/core/Akka.Persistence.TestKit/Journal/TestJournal.cs @@ -5,6 +5,8 @@ // //----------------------------------------------------------------------- +using System.Threading; + namespace Akka.Persistence.TestKit { using Akka.Actor; @@ -48,7 +50,7 @@ protected override bool ReceivePluginInternal(object message) } } - protected override async Task> WriteMessagesAsync(IEnumerable messages) + protected override async Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { await _connectionInterceptor.InterceptAsync(); var exceptions = new List(); @@ -90,10 +92,10 @@ public override async Task ReplayMessagesAsync(IActorContext context, string per } } - public override async Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) + public override async Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken) { await _connectionInterceptor.InterceptAsync(); - return await base.ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr); + return await base.ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr, cancellationToken); } /// diff --git a/src/core/Akka.Persistence.TestKit/SnapshotStore/TestSnapshotStore.cs b/src/core/Akka.Persistence.TestKit/SnapshotStore/TestSnapshotStore.cs index d71a319f885..6deca02ebca 100644 --- a/src/core/Akka.Persistence.TestKit/SnapshotStore/TestSnapshotStore.cs +++ b/src/core/Akka.Persistence.TestKit/SnapshotStore/TestSnapshotStore.cs @@ -5,6 +5,9 @@ // //----------------------------------------------------------------------- +using System.Runtime.CompilerServices; +using System.Threading; + namespace Akka.Persistence.TestKit { using System.Threading.Tasks; @@ -50,35 +53,36 @@ protected override bool ReceivePluginInternal(object message) } } - protected override async Task SaveAsync(SnapshotMetadata metadata, object snapshot) + protected override async Task SaveAsync(SnapshotMetadata metadata, object snapshot, CancellationToken cancellationToken) { await _connectionInterceptor.InterceptAsync(); await _saveInterceptor.InterceptAsync(metadata.PersistenceId, ToSelectionCriteria(metadata)); - await base.SaveAsync(metadata, snapshot); + await base.SaveAsync(metadata, snapshot, cancellationToken); } - protected override async Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) + protected override async Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { await _connectionInterceptor.InterceptAsync(); await _loadInterceptor.InterceptAsync(persistenceId, criteria); - return await base.LoadAsync(persistenceId, criteria); + return await base.LoadAsync(persistenceId, criteria, cancellationToken); } - protected override async Task DeleteAsync(SnapshotMetadata metadata) + protected override async Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { await _connectionInterceptor.InterceptAsync(); await _deleteInterceptor.InterceptAsync(metadata.PersistenceId, ToSelectionCriteria(metadata)); - await base.DeleteAsync(metadata); + await base.DeleteAsync(metadata, cancellationToken); } - protected override async Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + protected override async Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { await _connectionInterceptor.InterceptAsync(); await _deleteInterceptor.InterceptAsync(persistenceId, criteria); - await base.DeleteAsync(persistenceId, criteria); + await base.DeleteAsync(persistenceId, criteria, cancellationToken); } - static SnapshotSelectionCriteria ToSelectionCriteria(SnapshotMetadata metadata) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static SnapshotSelectionCriteria ToSelectionCriteria(SnapshotMetadata metadata) => new(metadata.SequenceNr, metadata.Timestamp, metadata.SequenceNr, metadata.Timestamp); /// diff --git a/src/core/Akka.Persistence.Tests/Journal/ChaosJournal.cs b/src/core/Akka.Persistence.Tests/Journal/ChaosJournal.cs index c33192df911..c2ba8de4af4 100644 --- a/src/core/Akka.Persistence.Tests/Journal/ChaosJournal.cs +++ b/src/core/Akka.Persistence.Tests/Journal/ChaosJournal.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Akka.Actor; using Akka.Persistence.Journal; @@ -83,7 +84,7 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten return promise.Task; } - public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) + public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken) { var promise = new TaskCompletionSource(); if (ChaosSupportExtensions.ShouldFail(_readHighestFailureRate)) @@ -93,7 +94,7 @@ public override Task ReadHighestSequenceNrAsync(string persistenceId, long return promise.Task; } - protected override Task> WriteMessagesAsync(IEnumerable messages) + protected override Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { var promise = new TaskCompletionSource>(); @@ -120,7 +121,7 @@ protected override Task> WriteMessagesAsync(IEnumerabl return promise.Task; } - protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) + protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, CancellationToken cancellationToken) { TaskCompletionSource promise = new TaskCompletionSource(); try diff --git a/src/core/Akka.Persistence.Tests/Journal/SteppingMemoryJournal.cs b/src/core/Akka.Persistence.Tests/Journal/SteppingMemoryJournal.cs index 18f5e0910c2..3f48d76e62c 100644 --- a/src/core/Akka.Persistence.Tests/Journal/SteppingMemoryJournal.cs +++ b/src/core/Akka.Persistence.Tests/Journal/SteppingMemoryJournal.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Akka.Actor; using Akka.Configuration; @@ -110,14 +111,14 @@ protected override void PostStop() _current.TryRemove(_instanceId, out foo); } - protected override Task> WriteMessagesAsync(IEnumerable messages) + protected override Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { var tasks = messages.Select(message => { return WrapAndDoOrEnqueue( () => - base.WriteMessagesAsync(new[] {message}) + base.WriteMessagesAsync(new[] {message}, cancellationToken) .ContinueWith(t => t.Result != null ? t.Result.FirstOrDefault() : null, _continuationOptions | TaskContinuationOptions.OnlyOnRanToCompletion)); }); @@ -127,19 +128,19 @@ protected override Task> WriteMessagesAsync(IEnumerabl _continuationOptions | TaskContinuationOptions.OnlyOnRanToCompletion); } - protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) + protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, CancellationToken cancellationToken) { return WrapAndDoOrEnqueue( () => - base.DeleteMessagesToAsync(persistenceId, toSequenceNr) + base.DeleteMessagesToAsync(persistenceId, toSequenceNr, cancellationToken) .ContinueWith(_ => new object(), _continuationOptions | TaskContinuationOptions.OnlyOnRanToCompletion)); } - public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) + public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken) { - return WrapAndDoOrEnqueue(() => base.ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr)); + return WrapAndDoOrEnqueue(() => base.ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr, cancellationToken)); } public override Task ReplayMessagesAsync(IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, diff --git a/src/core/Akka.Persistence.Tests/PersistentActorDeleteFailureSpec.cs b/src/core/Akka.Persistence.Tests/PersistentActorDeleteFailureSpec.cs index 883f48a4101..5df784c610b 100644 --- a/src/core/Akka.Persistence.Tests/PersistentActorDeleteFailureSpec.cs +++ b/src/core/Akka.Persistence.Tests/PersistentActorDeleteFailureSpec.cs @@ -6,6 +6,7 @@ //----------------------------------------------------------------------- using System; +using System.Threading; using System.Threading.Tasks; using Akka.Actor; using Akka.Event; @@ -41,7 +42,7 @@ public SimulatedException(string message) : base(message) public class DeleteFailingMemoryJournal : MemoryJournal { - protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) + protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, CancellationToken cancellationToken) { var promise = new TaskCompletionSource(); promise.SetException(new SimulatedException("Boom! Unable to delete events!")); diff --git a/src/core/Akka.Persistence.Tests/PersistentActorFailureSpec.cs b/src/core/Akka.Persistence.Tests/PersistentActorFailureSpec.cs index 65239940374..5922a65be8e 100644 --- a/src/core/Akka.Persistence.Tests/PersistentActorFailureSpec.cs +++ b/src/core/Akka.Persistence.Tests/PersistentActorFailureSpec.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Akka.Actor; using Akka.Persistence.Journal; @@ -49,7 +50,7 @@ public SimulatedSerializationException(string message) : base(message) internal class FailingMemoryJournal : MemoryJournal { - protected override Task> WriteMessagesAsync(IEnumerable messages) + protected override Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { var msgs = messages.ToList(); if (IsWrong(msgs)) @@ -59,7 +60,7 @@ protected override Task> WriteMessagesAsync(IEnumerabl { return Task.FromResult(checkSerializable); } - return base.WriteMessagesAsync(msgs); + return base.WriteMessagesAsync(msgs, cancellationToken); } public override Task ReplayMessagesAsync(IActorContext context, string persistenceId, long fromSequenceNr, diff --git a/src/core/Akka.Persistence.Tests/SnapshotFailureRobustnessSpec.cs b/src/core/Akka.Persistence.Tests/SnapshotFailureRobustnessSpec.cs index 800f46996d4..c5d39b3f01b 100644 --- a/src/core/Akka.Persistence.Tests/SnapshotFailureRobustnessSpec.cs +++ b/src/core/Akka.Persistence.Tests/SnapshotFailureRobustnessSpec.cs @@ -9,6 +9,7 @@ using System.IO; using System.Linq; using System.Text; +using System.Threading; using System.Threading.Tasks; using Akka.Actor; using Akka.Event; @@ -168,22 +169,16 @@ protected override void Save(SnapshotMetadata metadata, object payload) internal class DeleteFailingLocalSnapshotStore : LocalSnapshotStore { - protected override Task DeleteAsync(SnapshotMetadata metadata) + protected override async Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { - base.DeleteAsync(metadata); // we actually delete it properly, but act as if it failed - var promise = new TaskCompletionSource(); - promise.SetException(new InvalidOperationException("Failed to delete snapshot for some reason.")); - return promise.Task; + await base.DeleteAsync(metadata, cancellationToken); // we actually delete it properly, but act as if it failed + throw new InvalidOperationException("Failed to delete snapshot for some reason."); } - protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + protected override async Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { -#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - base.DeleteAsync(persistenceId, criteria); // we actually delete it properly, but act as if it failed -#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed - var promise = new TaskCompletionSource(); - promise.SetException(new InvalidOperationException("Failed to delete snapshot for some reason.")); - return promise.Task; + await base.DeleteAsync(persistenceId, criteria, cancellationToken); // we actually delete it properly, but act as if it failed + throw new InvalidOperationException("Failed to delete snapshot for some reason."); } } diff --git a/src/core/Akka.Persistence/Journal/AsyncRecovery.cs b/src/core/Akka.Persistence/Journal/AsyncRecovery.cs index 8f4cfe7a030..b88562b2908 100644 --- a/src/core/Akka.Persistence/Journal/AsyncRecovery.cs +++ b/src/core/Akka.Persistence/Journal/AsyncRecovery.cs @@ -6,6 +6,7 @@ //----------------------------------------------------------------------- using System; +using System.Threading; using System.Threading.Tasks; using Akka.Actor; @@ -62,7 +63,8 @@ public interface IAsyncRecovery /// Hint where to start searching for the highest sequence number. /// When a persistent actor is recovering this will the sequence /// number of the used snapshot, or `0L` if no snapshot is used. + /// used to signal cancelled recovery operation /// TBD - Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); + Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken); } } diff --git a/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs b/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs index 55b09aefd1e..0d8a8b2b21d 100644 --- a/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs +++ b/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs @@ -9,6 +9,8 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; using System.Threading.Tasks; using Akka.Actor; using Akka.Pattern; @@ -54,9 +56,9 @@ protected AsyncWriteJournal() var config = extension.ConfigFor(Self); _breaker = new CircuitBreaker( Context.System.Scheduler, - config.GetInt("circuit-breaker.max-failures", 0), - config.GetTimeSpan("circuit-breaker.call-timeout", null), - config.GetTimeSpan("circuit-breaker.reset-timeout", null)); + config.GetInt("circuit-breaker.max-failures", 10), + config.GetTimeSpan("circuit-breaker.call-timeout", TimeSpan.FromSeconds(10)), + config.GetTimeSpan("circuit-breaker.reset-timeout", TimeSpan.FromSeconds(30))); var replayFilterMode = config.GetString("replay-filter.mode", "").ToLowerInvariant(); switch (replayFilterMode) @@ -88,7 +90,7 @@ protected AsyncWriteJournal() public abstract Task ReplayMessagesAsync(IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, Action recoveryCallback); /// - public abstract Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); + public abstract Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken); /// /// Plugin API: asynchronously writes a batch of persistent messages to the @@ -161,8 +163,8 @@ protected AsyncWriteJournal() /// This call is protected with a circuit-breaker. /// /// TBD - /// TBD - protected abstract Task> WriteMessagesAsync(IEnumerable messages); + /// used to signal cancelled snapshot operation + protected abstract Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken); /// /// Asynchronously deletes all persistent messages up to inclusive @@ -170,8 +172,8 @@ protected AsyncWriteJournal() /// /// TBD /// TBD - /// TBD - protected abstract Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr); + /// used to signal cancelled snapshot operation + protected abstract Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, CancellationToken cancellationToken); /// /// Plugin API: Allows plugin implementers to use f.PipeTo(Self) @@ -222,8 +224,8 @@ async Task ProcessDelete() { try { - await _breaker.WithCircuitBreaker((message, awj: this), state => - state.awj.DeleteMessagesToAsync(state.message.PersistenceId, state.message.ToSequenceNr)); + await _breaker.WithCircuitBreaker((message, awj: this), (state, ct) => + state.awj.DeleteMessagesToAsync(state.message.PersistenceId, state.message.ToSequenceNr, ct)); message.PersistentActor.Tell(new DeleteMessagesSuccess(message.ToSequenceNr), self); @@ -259,26 +261,14 @@ private void HandleReplayMessages(ReplayMessages message) async Task ExecuteHighestSequenceNr() { - void CompleteHighSeqNo(long highSeqNo) - { - replyTo.Tell(new RecoverySuccess(highSeqNo)); - - if (CanPublish) - { - eventStream.Publish(message); - } - } - try { - var highSequenceNr = await _breaker.WithCircuitBreaker((message, readHighestSequenceNrFrom, awj: this), state => - state.awj.ReadHighestSequenceNrAsync(state.message.PersistenceId, state.readHighestSequenceNrFrom)); + var highSequenceNr = await _breaker.WithCircuitBreaker( + (message, readHighestSequenceNrFrom, awj: this), + (state, ct) => + state.awj.ReadHighestSequenceNrAsync(state.message.PersistenceId, state.readHighestSequenceNrFrom, ct)); var toSequenceNr = Math.Min(message.ToSequenceNr, highSequenceNr); - if (toSequenceNr <= 0L || message.FromSequenceNr > toSequenceNr) - { - CompleteHighSeqNo(highSequenceNr); - } - else + if (toSequenceNr > 0L && message.FromSequenceNr <= toSequenceNr) { // Send replayed messages and replay result to persistentActor directly. No need // to resequence replayed messages relative to written and looped messages. @@ -294,8 +284,13 @@ await ReplayMessagesAsync(context, message.PersistenceId, message.FromSequenceNr } } }); + } + + replyTo.Tell(new RecoverySuccess(highSequenceNr)); - CompleteHighSeqNo(highSequenceNr); + if (CanPublish) + { + eventStream.Publish(message); } } catch (OperationCanceledException cx) @@ -357,7 +352,9 @@ private async Task ExecuteBatch(WriteMessages message, int atomicWriteCount, IAc try { var writeResult = - await _breaker.WithCircuitBreaker((prepared, awj: this), state => state.awj.WriteMessagesAsync(state.prepared)).ConfigureAwait(false); + await _breaker.WithCircuitBreaker( + state: (prepared, awj: this), + body: (state, ct) => state.awj.WriteMessagesAsync(state.prepared, ct)).ConfigureAwait(false); ProcessResults(writeResult, atomicWriteCount, message, _resequencer, resequencerCounter, self); } @@ -388,34 +385,51 @@ private void ProcessResults(IImmutableList results, int atomicWriteCo : new WriteMessageRejected(x, exception, writeMessage.ActorInstanceId), results, resequencerCounter, writeMessage, resequencer, writeJournal); } - private void Resequence(Func mapper, - IImmutableList results, long resequencerCounter, WriteMessages msg, IActorRef resequencer, IActorRef writeJournal) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static void Resequence( + Func mapper, + IImmutableList results, + long resequencerCounter, + WriteMessages msg, + IActorRef resequencer, + IActorRef writeJournal) { var i = 0; var enumerator = results?.GetEnumerator(); - foreach (var resequencable in msg.Messages) + try { - if (resequencable is AtomicWrite aw) + foreach (var resequencable in msg.Messages) { - Exception exception = null; - if (enumerator != null) + if (resequencable is AtomicWrite aw) { - enumerator.MoveNext(); - exception = enumerator.Current; + Exception exception = null; + if (enumerator != null) + { + enumerator.MoveNext(); + exception = enumerator.Current; + } + + foreach (var p in (IEnumerable)aw.Payload) + { + resequencer.Tell( + new Desequenced(mapper(p, exception), resequencerCounter + i + 1, msg.PersistentActor, + p.Sender), writeJournal); + i++; + } } - - foreach (var p in (IEnumerable)aw.Payload) + else { - resequencer.Tell(new Desequenced(mapper(p, exception), resequencerCounter + i + 1, msg.PersistentActor, p.Sender), writeJournal); + var loopMsg = new LoopMessageSuccess(resequencable.Payload, msg.ActorInstanceId); + resequencer.Tell( + new Desequenced(loopMsg, resequencerCounter + i + 1, msg.PersistentActor, + resequencable.Sender), writeJournal); i++; } } - else - { - var loopMsg = new LoopMessageSuccess(resequencable.Payload, msg.ActorInstanceId); - resequencer.Tell(new Desequenced(loopMsg, resequencerCounter + i + 1, msg.PersistentActor, resequencable.Sender), writeJournal); - i++; - } + } + finally + { + enumerator?.Dispose(); } } diff --git a/src/core/Akka.Persistence/Journal/AsyncWriteProxy.cs b/src/core/Akka.Persistence/Journal/AsyncWriteProxy.cs index 28e57c51c46..1f3c8662642 100644 --- a/src/core/Akka.Persistence/Journal/AsyncWriteProxy.cs +++ b/src/core/Akka.Persistence/Journal/AsyncWriteProxy.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; using Akka.Actor; using System.Runtime.Serialization; +using System.Threading; namespace Akka.Persistence.Journal { @@ -324,16 +325,21 @@ protected internal override bool AroundReceive(Receive receive, object message) /// TBD /// /// TBD + /// used to signal cancelled snapshot operation /// /// This exception is thrown when the store has not been initialized. /// /// TBD - protected override Task> WriteMessagesAsync(IEnumerable messages) + protected override async Task> WriteMessagesAsync( + IEnumerable messages, + CancellationToken cancellationToken) { if (_store == null) - return StoreNotInitialized>(); + throw new TimeoutException("Store not initialized."); - return _store.Ask>(new AsyncWriteTarget.WriteMessages(messages), Timeout); + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(Timeout); + return await _store.Ask>(new AsyncWriteTarget.WriteMessages(messages), cts.Token); } /// @@ -341,16 +347,22 @@ protected override Task> WriteMessagesAsync(IEnumerabl /// /// TBD /// TBD + /// used to signal cancelled snapshot operation /// /// This exception is thrown when the store has not been initialized. /// /// TBD - protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) + protected override async Task DeleteMessagesToAsync( + string persistenceId, + long toSequenceNr, + CancellationToken cancellationToken) { if (_store == null) - return StoreNotInitialized(); + throw new TimeoutException("Store not initialized."); - return _store.Ask(new AsyncWriteTarget.DeleteMessagesTo(persistenceId, toSequenceNr), Timeout); + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(Timeout); + await _store.Ask(new AsyncWriteTarget.DeleteMessagesTo(persistenceId, toSequenceNr), cts.Token); } /// @@ -384,17 +396,22 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten /// /// TBD /// TBD + /// used to signal cancelled snapshot operation /// /// This exception is thrown when the store has not been initialized. /// /// TBD - public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) + public override async Task ReadHighestSequenceNrAsync( + string persistenceId, + long fromSequenceNr, + CancellationToken cancellationToken) { if (_store == null) - return StoreNotInitialized(); + throw new TimeoutException("Store not initialized."); - return _store.Ask(new AsyncWriteTarget.ReplayMessages(persistenceId, 0, 0, 0), Timeout) - .ContinueWith(t => t.Result.HighestSequenceNr, TaskContinuationOptions.OnlyOnRanToCompletion); + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); + cts.CancelAfter(Timeout); + return (await _store.Ask(new AsyncWriteTarget.ReplayMessages(persistenceId, 0, 0, 0), cts.Token)).HighestSequenceNr; } private Task StoreNotInitialized() diff --git a/src/core/Akka.Persistence/Journal/MemoryJournal.cs b/src/core/Akka.Persistence/Journal/MemoryJournal.cs index 995ed6b4b84..d335d42d300 100644 --- a/src/core/Akka.Persistence/Journal/MemoryJournal.cs +++ b/src/core/Akka.Persistence/Journal/MemoryJournal.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Akka.Actor; using Akka.Event; @@ -31,7 +32,7 @@ public class MemoryJournal : AsyncWriteJournal protected virtual ConcurrentDictionary> Messages { get { return _messages; } } - protected override Task> WriteMessagesAsync(IEnumerable messages) + protected override Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { foreach (var w in messages) { @@ -59,7 +60,7 @@ protected override Task> WriteMessagesAsync(IEnumerabl return Task.FromResult>(null); // all good } - public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) + public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken) { return Task.FromResult(Math.Max(HighestSequenceNr(persistenceId), _meta.GetValueOrDefault(persistenceId, 0L))); } @@ -73,7 +74,7 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten return Task.CompletedTask; } - protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) + protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, CancellationToken cancellationToken) { var highestSeqNr = HighestSequenceNr(persistenceId); var toSeqNr = Math.Min(toSequenceNr, highestSeqNr); diff --git a/src/core/Akka.Persistence/Snapshot/LocalSnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/LocalSnapshotStore.cs index 9dbcdb54f93..9c1d8196c2c 100644 --- a/src/core/Akka.Persistence/Snapshot/LocalSnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/LocalSnapshotStore.cs @@ -11,6 +11,7 @@ using System.IO; using System.Linq; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Akka.Dispatch; using Akka.Event; @@ -67,7 +68,7 @@ public LocalSnapshotStore() private readonly ILoggingAdapter _log; /// - protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) + protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { // // Heuristics: @@ -81,7 +82,7 @@ protected override Task LoadAsync(string persistenceId, Snapsh } /// - protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) + protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot, CancellationToken cancellationToken) { _saving.Add(metadata); return RunWithStreamDispatcher(() => @@ -92,7 +93,7 @@ protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) } /// - protected override Task DeleteAsync(SnapshotMetadata metadata) + protected override Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { _saving.Remove(metadata); return RunWithStreamDispatcher(() => @@ -109,11 +110,11 @@ protected override Task DeleteAsync(SnapshotMetadata metadata) } /// - protected override async Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + protected override async Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { foreach (var metadata in GetSnapshotMetadata(persistenceId, criteria)) { - await DeleteAsync(metadata); + await DeleteAsync(metadata, cancellationToken); } } diff --git a/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs index 3e87eb80634..3664ecdeab3 100644 --- a/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs @@ -8,6 +8,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.CompilerServices; +using System.Threading; using System.Threading.Tasks; using Akka.Util.Internal; @@ -25,19 +27,20 @@ public class MemorySnapshotStore : SnapshotStore /// protected virtual List Snapshots { get; } = new(); - protected override Task DeleteAsync(SnapshotMetadata metadata) + protected override Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { - bool Pred(SnapshotEntry x) => x.PersistenceId == metadata.PersistenceId && (metadata.SequenceNr <= 0 || metadata.SequenceNr == long.MaxValue || x.SequenceNr == metadata.SequenceNr) - && (metadata.Timestamp == DateTime.MinValue || metadata.Timestamp == DateTime.MaxValue || x.Timestamp == metadata.Timestamp.Ticks); - - var snapshot = Snapshots.FirstOrDefault(Pred); Snapshots.Remove(snapshot); return TaskEx.Completed; + + bool Pred(SnapshotEntry x) => + x.PersistenceId == metadata.PersistenceId + && (metadata.SequenceNr <= 0 || metadata.SequenceNr == long.MaxValue || x.SequenceNr == metadata.SequenceNr) + && (metadata.Timestamp == DateTime.MinValue || metadata.Timestamp == DateTime.MaxValue || x.Timestamp == metadata.Timestamp.Ticks); } - protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { var filter = CreateRangeFilter(persistenceId, criteria); @@ -45,7 +48,7 @@ protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCrite return TaskEx.Completed; } - protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) + protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { var filter = CreateRangeFilter(persistenceId, criteria); @@ -54,7 +57,7 @@ protected override Task LoadAsync(string persistenceId, Snapsh return Task.FromResult(snapshot); } - protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) + protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot, CancellationToken cancellationToken) { var snapshotEntry = ToSnapshotEntry(metadata, snapshot); @@ -78,7 +81,8 @@ private static Func CreateSnapshotIdFilter(string snapshotI return x => x.Id == snapshotId; } - private Func CreateRangeFilter(string persistenceId, SnapshotSelectionCriteria criteria) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Func CreateRangeFilter(string persistenceId, SnapshotSelectionCriteria criteria) { return (x => x.PersistenceId == persistenceId && (criteria.MaxSequenceNr <= 0 || criteria.MaxSequenceNr == long.MaxValue || x.SequenceNr <= criteria.MaxSequenceNr) && diff --git a/src/core/Akka.Persistence/Snapshot/NoSnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/NoSnapshotStore.cs index 7b3d6a66a12..7f66b3ecbc3 100644 --- a/src/core/Akka.Persistence/Snapshot/NoSnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/NoSnapshotStore.cs @@ -6,7 +6,9 @@ //----------------------------------------------------------------------- using System; +using System.Runtime.CompilerServices; using System.Runtime.Serialization; +using System.Threading; using System.Threading.Tasks; namespace Akka.Persistence.Snapshot @@ -59,59 +61,37 @@ protected NoSnapshotStoreException(SerializationInfo info, StreamingContext cont } } - /// - /// TBD - /// - /// TBD - /// TBD - /// TBD - protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) + protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { return Task.FromResult((SelectedSnapshot)null); } - /// - /// TBD - /// - /// TBD - /// TBD /// /// This exception is thrown when no snapshot store is configured. /// - /// TBD - protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) + protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot, CancellationToken cancellationToken) { return Flop(); } - /// - /// TBD - /// - /// TBD /// /// This exception is thrown when no snapshot store is configured. /// - /// TBD - protected override Task DeleteAsync(SnapshotMetadata metadata) + protected override Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { return Flop(); } - /// - /// TBD - /// - /// TBD - /// TBD /// /// This exception is thrown when no snapshot store is configured. /// - /// TBD - protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { return Flop(); } - private Task Flop() + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Task Flop() { var promise = new TaskCompletionSource(); promise.SetException(new NoSnapshotStoreException("No snapshot store configured.")); diff --git a/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs index 33a5623b758..645f7e7f776 100644 --- a/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs @@ -6,6 +6,8 @@ //----------------------------------------------------------------------- using System; +using System.Runtime.CompilerServices; +using System.Threading; using System.Threading.Tasks; using Akka.Actor; using Akka.Event; @@ -59,155 +61,206 @@ private bool ReceiveSnapshotStore(object message) var senderPersistentActor = Sender; // Sender is PersistentActor var self = Self; //Self MUST BE CLOSED OVER here, or the code below will be subject to race conditions - if (message is LoadSnapshot loadSnapshot) + switch (message) { - if (loadSnapshot.Criteria == SnapshotSelectionCriteria.None) - { + case LoadSnapshot loadSnapshot when loadSnapshot.Criteria.Equals(SnapshotSelectionCriteria.None): senderPersistentActor.Tell(new LoadSnapshotResult(null, loadSnapshot.ToSequenceNr)); - } - else - { - _breaker.WithCircuitBreaker(() => LoadAsync(loadSnapshot.PersistenceId, loadSnapshot.Criteria.Limit(loadSnapshot.ToSequenceNr))) - .ContinueWith(t => (!t.IsFaulted && !t.IsCanceled) - ? new LoadSnapshotResult(t.Result, loadSnapshot.ToSequenceNr) as ISnapshotResponse - : new LoadSnapshotFailed(t.IsFaulted - ? TryUnwrapException(t.Exception) - : new OperationCanceledException("LoadAsync canceled, possibly due to timing out.")), - _continuationOptions) + break; + + case LoadSnapshot loadSnapshot: + _breaker.WithCircuitBreaker(InvokeLoadAsync) .PipeTo(senderPersistentActor); - } - } - else if (message is SaveSnapshot saveSnapshot) - { - var metadata = new SnapshotMetadata(saveSnapshot.Metadata.PersistenceId, saveSnapshot.Metadata.SequenceNr, saveSnapshot.Metadata.Timestamp == DateTime.MinValue ? DateTime.UtcNow : saveSnapshot.Metadata.Timestamp); + break; - _breaker.WithCircuitBreaker(() => SaveAsync(metadata, saveSnapshot.Snapshot)) - .ContinueWith(t => (!t.IsFaulted && !t.IsCanceled) - ? new SaveSnapshotSuccess(metadata) as ISnapshotResponse - : new SaveSnapshotFailure(saveSnapshot.Metadata, - t.IsFaulted - ? TryUnwrapException(t.Exception) - : new OperationCanceledException("SaveAsync canceled, possibly due to timing out.", TryUnwrapException(t.Exception))), - _continuationOptions) - .PipeTo(self, senderPersistentActor); - } - else if (message is SaveSnapshotSuccess) - { - try - { - ReceivePluginInternal(message); - } - finally - { - senderPersistentActor.Tell(message); - } - } - else if (message is SaveSnapshotFailure saveSnapshotFailure) - { - try - { - ReceivePluginInternal(message); - _breaker.WithCircuitBreaker(() => DeleteAsync(saveSnapshotFailure.Metadata)) - .ContinueWith(t => + async Task InvokeLoadAsync(CancellationToken cancellationToken) + { + try { - if(t.IsFaulted) - _log.Error(t.Exception, "DeleteAsync operation after SaveSnapshot failure failed."); - else if(t.IsCanceled) - _log.Error(t.Exception, t.Exception is not null - ? "DeleteAsync operation after SaveSnapshot failure canceled." - : "DeleteAsync operation after SaveSnapshot failure canceled, possibly due to timing out."); - }, TaskContinuationOptions.ExecuteSynchronously); - } - finally - { - senderPersistentActor.Tell(message); - } - } - else if (message is DeleteSnapshot deleteSnapshot) - { - var eventStream = Context.System.EventStream; - _breaker.WithCircuitBreaker(() => DeleteAsync(deleteSnapshot.Metadata)) - .ContinueWith(t => (!t.IsFaulted && !t.IsCanceled) - ? new DeleteSnapshotSuccess(deleteSnapshot.Metadata) as ISnapshotResponse - : new DeleteSnapshotFailure(deleteSnapshot.Metadata, - t.IsFaulted - ? TryUnwrapException(t.Exception) - : new OperationCanceledException("DeleteAsync canceled, possibly due to timing out.")), - _continuationOptions) - .PipeTo(self, senderPersistentActor) - .ContinueWith(_ => + return new LoadSnapshotResult( + snapshot: await LoadAsync( + persistenceId: loadSnapshot.PersistenceId, + criteria: loadSnapshot.Criteria.Limit(loadSnapshot.ToSequenceNr), + cancellationToken: cancellationToken), + toSequenceNr: loadSnapshot.ToSequenceNr); + } + catch (Exception e) + { + return new LoadSnapshotFailed(TryUnwrapException(e)); + } + } + + case SaveSnapshot saveSnapshot: + var metadata = new SnapshotMetadata( + persistenceId: saveSnapshot.Metadata.PersistenceId, + sequenceNr: saveSnapshot.Metadata.SequenceNr, + timestamp: saveSnapshot.Metadata.Timestamp == DateTime.MinValue + ? DateTime.UtcNow + : saveSnapshot.Metadata.Timestamp); + + _breaker.WithCircuitBreaker(InvokeSaveAsync) + .PipeTo(self, senderPersistentActor); + + break; + + async Task InvokeSaveAsync(CancellationToken cancellationToken) { - if (_publish) - eventStream.Publish(message); - }, _continuationOptions); - } - else if (message is DeleteSnapshotSuccess) - { - try - { - ReceivePluginInternal(message); - } - finally - { - senderPersistentActor.Tell(message); - } - } - else if (message is DeleteSnapshotFailure) - { - try - { - ReceivePluginInternal(message); - } - finally - { - senderPersistentActor.Tell(message); - } - } - else if (message is DeleteSnapshots deleteSnapshots) - { - var eventStream = Context.System.EventStream; - _breaker.WithCircuitBreaker(() => DeleteAsync(deleteSnapshots.PersistenceId, deleteSnapshots.Criteria)) - .ContinueWith(t => (!t.IsFaulted && !t.IsCanceled) - ? new DeleteSnapshotsSuccess(deleteSnapshots.Criteria) as ISnapshotResponse - : new DeleteSnapshotsFailure(deleteSnapshots.Criteria, - t.IsFaulted - ? TryUnwrapException(t.Exception) - : new OperationCanceledException("DeleteAsync canceled, possibly due to timing out.")), - _continuationOptions) - .PipeTo(self, senderPersistentActor) - .ContinueWith(_ => + try + { + await SaveAsync(metadata, saveSnapshot.Snapshot, cancellationToken); + return new SaveSnapshotSuccess(metadata); + } + catch (Exception e) + { + return new SaveSnapshotFailure(saveSnapshot.Metadata, TryUnwrapException(e)); + } + } + + case SaveSnapshotSuccess: + try { - if (_publish) - eventStream.Publish(message); - }, _continuationOptions); - } - else if (message is DeleteSnapshotsSuccess) - { - try - { - ReceivePluginInternal(message); - } - finally - { - senderPersistentActor.Tell(message); - } - } - else if (message is DeleteSnapshotsFailure) - { - try + ReceivePluginInternal(message); + } + finally + { + senderPersistentActor.Tell(message); + } + + break; + + case SaveSnapshotFailure saveSnapshotFailure: + try + { + ReceivePluginInternal(message); + _breaker.WithCircuitBreaker(InvokeDeleteAsync); + + async Task InvokeDeleteAsync(CancellationToken cancellationToken) + { + try + { + await DeleteAsync(saveSnapshotFailure.Metadata, cancellationToken); + } + catch (Exception e) + { + _log.Error(TryUnwrapException(e), "DeleteAsync operation after SaveSnapshot failure failed."); + } + } + } + finally + { + senderPersistentActor.Tell(message); + } + + break; + + case DeleteSnapshot deleteSnapshot: { - ReceivePluginInternal(message); + var eventStream = Context.System.EventStream; + _breaker.WithCircuitBreaker(InvokeDeleteAsync) + .PipeTo(self, senderPersistentActor) + .ContinueWith(_ => + { + if (_publish) + eventStream.Publish(message); + }, _continuationOptions); + + break; + + async Task InvokeDeleteAsync(CancellationToken cancellationToken) + { + try + { + await DeleteAsync(deleteSnapshot.Metadata, cancellationToken); + return new DeleteSnapshotSuccess(deleteSnapshot.Metadata); + } + catch (Exception e) + { + return new DeleteSnapshotFailure(deleteSnapshot.Metadata, TryUnwrapException(e)); + } + } } - finally + + case DeleteSnapshotSuccess: + try + { + ReceivePluginInternal(message); + } + finally + { + senderPersistentActor.Tell(message); + } + + break; + + case DeleteSnapshotFailure: + try + { + ReceivePluginInternal(message); + } + finally + { + senderPersistentActor.Tell(message); + } + + break; + + case DeleteSnapshots deleteSnapshots: { - senderPersistentActor.Tell(message); + var eventStream = Context.System.EventStream; + _breaker.WithCircuitBreaker(InvokeDeleteAsync) + .PipeTo(self, senderPersistentActor) + .ContinueWith(_ => + { + if (_publish) + eventStream.Publish(message); + }, _continuationOptions); + break; + + async Task InvokeDeleteAsync(CancellationToken cancellationToken) + { + try + { + await DeleteAsync(deleteSnapshots.PersistenceId, deleteSnapshots.Criteria, cancellationToken); + return new DeleteSnapshotsSuccess(deleteSnapshots.Criteria); + } + catch (Exception e) + { + return new DeleteSnapshotsFailure(deleteSnapshots.Criteria, TryUnwrapException(e)); + } + } } + + case DeleteSnapshotsSuccess: + try + { + ReceivePluginInternal(message); + } + finally + { + senderPersistentActor.Tell(message); + } + + break; + + case DeleteSnapshotsFailure: + try + { + ReceivePluginInternal(message); + } + finally + { + senderPersistentActor.Tell(message); + } + + break; + + default: + return false; } - else return false; return true; } - private Exception TryUnwrapException(Exception e) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Exception TryUnwrapException(Exception e) { if (e is AggregateException aggregateException) { @@ -225,8 +278,11 @@ private Exception TryUnwrapException(Exception e) /// /// Id of the persistent actor. /// Selection criteria for loading. - /// TBD - protected abstract Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria); + /// used to signal cancelled snapshot operation + protected abstract Task LoadAsync( + string persistenceId, + SnapshotSelectionCriteria criteria, + CancellationToken cancellationToken); /// /// Plugin API: Asynchronously saves a snapshot. @@ -235,8 +291,11 @@ private Exception TryUnwrapException(Exception e) /// /// Snapshot metadata. /// Snapshot. - /// TBD - protected abstract Task SaveAsync(SnapshotMetadata metadata, object snapshot); + /// used to signal cancelled snapshot operation + protected abstract Task SaveAsync( + SnapshotMetadata metadata, + object snapshot, + CancellationToken cancellationToken); /// /// Plugin API: Deletes the snapshot identified by . @@ -244,8 +303,8 @@ private Exception TryUnwrapException(Exception e) /// This call is protected with a circuit-breaker /// /// Snapshot metadata. - /// TBD - protected abstract Task DeleteAsync(SnapshotMetadata metadata); + /// used to signal cancelled snapshot operation + protected abstract Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken); /// /// Plugin API: Deletes all snapshots matching provided . @@ -254,8 +313,11 @@ private Exception TryUnwrapException(Exception e) /// /// Id of the persistent actor. /// Selection criteria for deleting. - /// TBD - protected abstract Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria); + /// used to signal cancelled snapshot operation + protected abstract Task DeleteAsync( + string persistenceId, + SnapshotSelectionCriteria criteria, + CancellationToken cancellationToken); /// /// Plugin API: Allows plugin implementers to use f.PipeTo(Self) diff --git a/src/core/Akka.Tests/Pattern/CircuitBreakerSpec.cs b/src/core/Akka.Tests/Pattern/CircuitBreakerSpec.cs index faf228cf602..61649c50811 100644 --- a/src/core/Akka.Tests/Pattern/CircuitBreakerSpec.cs +++ b/src/core/Akka.Tests/Pattern/CircuitBreakerSpec.cs @@ -200,7 +200,7 @@ public class AnAsynchronousCircuitBreakerThatIsClosed : CircuitBreakerSpecBase public async Task Must_allow_calls_through() { var breaker = LongCallTimeoutCb(); - var result = await breaker.Instance.WithCircuitBreaker(() => Task.Run(SayHi)).WaitAsync(AwaitTimeout); + var result = await breaker.Instance.WithCircuitBreaker(ct => Task.Run(SayHi, ct)).WaitAsync(AwaitTimeout); Assert.Equal("hi", result); } @@ -209,7 +209,7 @@ public async Task Must_increment_failure_count_on_exception() { var breaker = LongCallTimeoutCb(); await InterceptException(() => - breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)).WaitAsync(AwaitTimeout)); + breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct)).WaitAsync(AwaitTimeout)); Assert.True(CheckLatch(breaker.OpenLatch)); breaker.Instance.CurrentFailureCount.ShouldBe(1); } @@ -218,7 +218,7 @@ await InterceptException(() => public void Must_increment_failure_count_on_async_failure() { var breaker = LongCallTimeoutCb(); - _ = breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)); + _ = breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct)); Assert.True(CheckLatch(breaker.OpenLatch)); breaker.Instance.CurrentFailureCount.ShouldBe(1); } @@ -227,10 +227,10 @@ public void Must_increment_failure_count_on_async_failure() public async Task Must_reset_failure_count_after_success() { var breaker = MultiFailureCb(); - await WaitForTaskToBeScheduled(breaker.Instance.WithCircuitBreaker(() => Task.Run(SayHi))); - await WaitForTaskToBeScheduled(Enumerable.Range(1, 4).Select(_ => breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException))).ToList()); + await WaitForTaskToBeScheduled(breaker.Instance.WithCircuitBreaker(ct => Task.Run(SayHi, ct))); + await WaitForTaskToBeScheduled(Enumerable.Range(1, 4).Select(_ => breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct))).ToList()); await AwaitAssertAsync(() => breaker.Instance.CurrentFailureCount.ShouldBe(4), AwaitTimeout); - await WaitForTaskToBeScheduled(breaker.Instance.WithCircuitBreaker(() => Task.Run(SayHi))); + await WaitForTaskToBeScheduled(breaker.Instance.WithCircuitBreaker(ct => Task.Run(SayHi, ct))); await AwaitAssertAsync(() => breaker.Instance.CurrentFailureCount.ShouldBe(0), AwaitTimeout); } @@ -239,9 +239,9 @@ public async Task Must_increment_failure_count_on_callTimeout() { var breaker = ShortCallTimeoutCb(); - var future = breaker.Instance.WithCircuitBreaker(async () => + var future = breaker.Instance.WithCircuitBreaker(async ct => { - await Task.Delay(150); + await Task.Delay(150, ct); ThrowException(); }); @@ -257,7 +257,7 @@ public async Task Must_increment_failure_count_on_callTimeout() public void Must_invoke_onOpen_if_call_fails_and_breaker_transits_to_open_state() { var breaker = ShortCallTimeoutCb(); - _ = breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)); + _ = breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct)); Assert.True(CheckLatch(breaker.OpenLatch)); } } @@ -268,9 +268,9 @@ public class AnAsynchronousCircuitBreakerThatIsHalfOpen : CircuitBreakerSpecBase public async Task Must_pass_through_next_call_and_close_on_success() { var breaker = ShortResetTimeoutCb(); - _ = breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)); + _ = breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct)); Assert.True(CheckLatch(breaker.HalfOpenLatch)); - var result = await breaker.Instance.WithCircuitBreaker(() => Task.Run(SayHi)).WaitAsync(AwaitTimeout); + var result = await breaker.Instance.WithCircuitBreaker(ct => Task.Run(SayHi, ct)).WaitAsync(AwaitTimeout); Assert.Equal("hi", result); Assert.True(CheckLatch(breaker.ClosedLatch)); } @@ -279,11 +279,11 @@ public async Task Must_pass_through_next_call_and_close_on_success() public async Task Must_reopen_on_exception_in_call() { var breaker = ShortResetTimeoutCb(); - _ = breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)); + _ = breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct)); Assert.True(CheckLatch(breaker.HalfOpenLatch)); breaker.OpenLatch.Reset(); await InterceptException(() => - breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)).WaitAsync(AwaitTimeout)); + breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct)).WaitAsync(AwaitTimeout)); Assert.True(CheckLatch(breaker.OpenLatch)); } @@ -291,11 +291,11 @@ await InterceptException(() => public void Must_reopen_on_async_failure() { var breaker = ShortResetTimeoutCb(); - _ = breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)); + _ = breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct)); Assert.True(CheckLatch(breaker.HalfOpenLatch)); breaker.OpenLatch.Reset(); - _ = breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)); + _ = breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct)); Assert.True(CheckLatch(breaker.OpenLatch)); } } @@ -306,19 +306,19 @@ public class AnAsynchronousCircuitBreakerThatIsOpen : CircuitBreakerSpecBase public async Task Must_throw_exceptions_when_called_before_reset_timeout() { var breaker = LongResetTimeoutCb(); - _ = breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)); + _ = breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct)); Assert.True(CheckLatch(breaker.OpenLatch)); await InterceptException( - () => breaker.Instance.WithCircuitBreaker(() => Task.Run(SayHi)).WaitAsync(AwaitTimeout)); + () => breaker.Instance.WithCircuitBreaker(ct => Task.Run(SayHi, ct)).WaitAsync(AwaitTimeout)); } [Fact(DisplayName = "An asynchronous circuit breaker that is open must transition to half-open on reset timeout")] public void Must_transition_to_half_open_on_reset_timeout() { var breaker = ShortResetTimeoutCb(); - _ = breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)); + _ = breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct)); Assert.True(CheckLatch(breaker.HalfOpenLatch)); } @@ -326,11 +326,11 @@ public void Must_transition_to_half_open_on_reset_timeout() public async Task Must_increase_reset_timeout_after_it_transits_to_open_again() { var breaker = NonOneFactorCb(); - _ = breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)); + _ = breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct)); Assert.True(CheckLatch(breaker.OpenLatch)); var e1 = await InterceptException( - () => breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException))); + () => breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct))); var shortRemainingDuration = e1.RemainingDuration; await Task.Delay(Dilated(TimeSpan.FromMilliseconds(1000))); @@ -338,11 +338,11 @@ public async Task Must_increase_reset_timeout_after_it_transits_to_open_again() // transit to open again breaker.OpenLatch.Reset(); - _ = breaker.Instance.WithCircuitBreaker(() => Task.Run(ThrowException)); + _ = breaker.Instance.WithCircuitBreaker(ct => Task.Run(ThrowException, ct)); Assert.True(CheckLatch(breaker.OpenLatch)); var e2 = await InterceptException(() => - breaker.Instance.WithCircuitBreaker(() => Task.FromResult(SayHi()))); + breaker.Instance.WithCircuitBreaker(_ => Task.FromResult(SayHi()))); var longRemainingDuration = e2.RemainingDuration; shortRemainingDuration.ShouldBeLessThan(longRemainingDuration); diff --git a/src/core/Akka.Tests/Pattern/CircuitBreakerStressSpec.cs b/src/core/Akka.Tests/Pattern/CircuitBreakerStressSpec.cs index cac56071432..b23a8ed3c3a 100644 --- a/src/core/Akka.Tests/Pattern/CircuitBreakerStressSpec.cs +++ b/src/core/Akka.Tests/Pattern/CircuitBreakerStressSpec.cs @@ -7,6 +7,7 @@ using System; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Akka.Actor; using Akka.Pattern; @@ -73,11 +74,11 @@ protected override void OnReceive(object message) case JobDone _: _doneCount++; break; - case Status.Failure { Cause: OpenCircuitException _ }: + case Status.Failure { Cause: OpenCircuitException }: _circCount++; _breaker.WithCircuitBreaker(Job).PipeTo(Self); break; - case Status.Failure { Cause: TimeoutException _ }: + case Status.Failure { Cause: TimeoutException }: _timeoutCount++; _breaker.WithCircuitBreaker(Job).PipeTo(Self); break; @@ -94,9 +95,9 @@ protected override void OnReceive(object message) } } - private static async Task Job() + private static async Task Job(CancellationToken ct) { - await Task.Delay(TimeSpan.FromMilliseconds(ThreadLocalRandom.Current.Next(300))); + await Task.Delay(TimeSpan.FromMilliseconds(ThreadLocalRandom.Current.Next(300)), ct); return JobDone.Instance; } } diff --git a/src/core/Akka/Pattern/CircuitBreaker.cs b/src/core/Akka/Pattern/CircuitBreaker.cs index cd192906585..df87ea0135c 100644 --- a/src/core/Akka/Pattern/CircuitBreaker.cs +++ b/src/core/Akka/Pattern/CircuitBreaker.cs @@ -7,7 +7,6 @@ using System; using System.Diagnostics; -using System.Runtime.ExceptionServices; using System.Threading; using System.Threading.Tasks; using Akka.Actor; @@ -221,43 +220,99 @@ public CircuitBreaker(IScheduler scheduler, int maxFailures, TimeSpan callTimeou /// /// Wraps invocation of asynchronous calls that need to be protected /// - /// TBD + /// The returned by the protected function /// Call needing protected /// containing the call result + [Obsolete(message:"Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] public Task WithCircuitBreaker(Func> body) => CurrentState.Invoke(body); + /// + /// Wraps invocation of asynchronous calls that need to be protected + /// + /// The returned by the protected function + /// Call needing protected + /// containing the call result + public Task WithCircuitBreaker(Func> body) => CurrentState.Invoke(body); + + /// + /// Wraps invocation of asynchronous calls that need to be protected + /// + /// The returned by the protected function + /// The of the state object passed into the protected function + /// The state object will be passed into the protected function during invocation + /// Call needing protected + /// containing the call result + [Obsolete(message:"Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] public Task WithCircuitBreaker(TState state, Func> body) => CurrentState.InvokeState(state, body); /// /// Wraps invocation of asynchronous calls that need to be protected /// + /// The returned by the protected function + /// The of the state object passed into the protected function + /// The state object will be passed into the protected function during invocation /// Call needing protected - /// + /// containing the call result + public Task WithCircuitBreaker(TState state, Func> body) => + CurrentState.InvokeState(state, body); + + /// + /// Wraps invocation of asynchronous calls that need to be protected + /// + /// Call needing protected + /// containing the call result + [Obsolete(message:"Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] public Task WithCircuitBreaker(Func body) => CurrentState.Invoke(body); + /// + /// Wraps invocation of asynchronous calls that need to be protected + /// + /// Call needing protected + /// containing the call result + public Task WithCircuitBreaker(Func body) => CurrentState.Invoke(body); + + /// + /// Wraps invocation of asynchronous calls that need to be protected + /// + /// The of the state object passed into the protected function + /// The state object will be passed into the protected function during invocation + /// Call needing protected + /// containing the call result + [Obsolete(message:"Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] public Task WithCircuitBreaker(TState state, Func body) => CurrentState.InvokeState(state, body); + /// + /// Wraps invocation of asynchronous calls that need to be protected + /// + /// The of the state object passed into the protected function + /// The state object will be passed into the protected function during invocation + /// Call needing protected + /// containing the call result + public Task WithCircuitBreaker(TState state, Func body) => + CurrentState.InvokeState(state, body); + /// /// Wraps invocations of asynchronous calls that need to be protected. /// /// Call needing protected public void WithSyncCircuitBreaker(Action body) => - WithCircuitBreaker(body, b => Task.Run(b)).GetAwaiter().GetResult(); + WithCircuitBreaker(body, (b, ct) => Task.Run(b, ct)).GetAwaiter().GetResult(); /// /// Wraps invocations of asynchronous calls that need to be protected. /// + /// The returned by the protected function /// Call needing protected /// The result of the call public T WithSyncCircuitBreaker(Func body) => - WithCircuitBreaker(body, b => Task.Run(b)).Result; + WithCircuitBreaker(body, (b, ct) => Task.Run(b, ct)).GetAwaiter().GetResult(); /// /// Mark a successful call through CircuitBreaker. Sometimes the callee of CircuitBreaker sends back a message to the /// caller Actor. In such a case, it is convenient to mark a successful call instead of using Future - /// via + /// via or /// public void Succeed() => _currentState.CallSucceeds(); @@ -266,7 +321,7 @@ public T WithSyncCircuitBreaker(Func body) => /// /// Mark a failed call through CircuitBreaker. Sometimes the callee of CircuitBreaker sends back a message to the /// caller Actor. In such a case, it is convenient to mark a failed call instead of using Future - /// via + /// via or /// public void Fail() => _currentState.CallFails(new UserCalledFailException()); @@ -274,7 +329,7 @@ public T WithSyncCircuitBreaker(Func body) => /// /// Return true if the internal state is Closed. WARNING: It is a "power API" call which you should use with care. - /// Ordinal use cases of CircuitBreaker expects a remote call to return Future, as in . + /// Ordinal use cases of CircuitBreaker expects a remote call to return Future, as in . /// So, if you check the state by yourself, and make a remote call outside CircuitBreaker, you should /// manage the state yourself. /// @@ -282,7 +337,7 @@ public T WithSyncCircuitBreaker(Func body) => /// /// Return true if the internal state is Open. WARNING: It is a "power API" call which you should use with care. - /// Ordinal use cases of CircuitBreaker expects a remote call to return Future, as in . + /// Ordinal use cases of CircuitBreaker expects a remote call to return Future, as in . /// So, if you check the state by yourself, and make a remote call outside CircuitBreaker, you should /// manage the state yourself. /// diff --git a/src/core/Akka/Pattern/CircuitBreakerState.cs b/src/core/Akka/Pattern/CircuitBreakerState.cs index 41683e787df..bafd2ea9d33 100644 --- a/src/core/Akka/Pattern/CircuitBreakerState.cs +++ b/src/core/Akka/Pattern/CircuitBreakerState.cs @@ -8,6 +8,7 @@ using System; using System.Diagnostics; using System.Globalization; +using System.Threading; using System.Threading.Tasks; using Akka.Util; using Akka.Util.Internal; @@ -45,31 +46,53 @@ private TimeSpan RemainingDuration() /// /// Fail-fast on any invocation /// - /// N/A + /// The return value of the invoked function /// Implementation of the call that needs protected /// containing result of protected call + [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter")] public override Task Invoke(Func> body) => Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); - public override Task - InvokeState(TState state, Func body) => - Task.FromException( - new OpenCircuitException(_breaker.LastCaughtException, - RemainingDuration())); + /// + /// Fail-fast on any invocation + /// + /// The return value of the invoked function + /// Implementation of the call that needs protected + /// containing result of protected call + public override Task Invoke(Func> body) => + Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); - public override Task InvokeState(TState state, - Func> body) => Task.FromException( - new OpenCircuitException(_breaker.LastCaughtException, - RemainingDuration())); + [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter")] + public override Task InvokeState(TState state, Func body) => + Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); + + public override Task InvokeState(TState state, Func body) => + Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); + + [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter")] + public override Task InvokeState(TState state, Func> body) => + Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); + + public override Task InvokeState(TState state, Func> body) => + Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); /// /// Fail-fast on any invocation /// /// Implementation of the call that needs protected /// containing result of protected call + [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter")] public override Task Invoke(Func body) => Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); + /// + /// Fail-fast on any invocation + /// + /// Implementation of the call that needs protected + /// containing result of protected call + public override Task Invoke(Func body) => + Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); + /// /// No-op for open, calls are never executed so cannot succeed or fail /// @@ -144,19 +167,53 @@ private void CheckState() /// Allows a single call through, during which all other callers fail-fast. If the call fails, the breaker reopens. /// If the call succeeds, the breaker closes. /// - /// TBD + /// The return value of the invoked function /// Implementation of the call that needs protected /// containing result of protected call + [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter")] public override Task Invoke(Func> body) { CheckState(); return CallThrough(body); } + /// + /// Allows a single call through, during which all other callers fail-fast. If the call fails, the breaker reopens. + /// If the call succeeds, the breaker closes. + /// + /// The return value of the invoked function + /// Implementation of the call that needs protected + /// containing result of protected call + public override Task Invoke(Func> body) + { + CheckState(); + return CallThrough(body); + } + + [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter")] public override Task InvokeState(TState state, Func> body) { CheckState(); - return CallThrough(state,body); + return CallThrough(state, body); + } + + public override Task InvokeState(TState state, Func> body) + { + CheckState(); + return CallThrough(state, body); + } + + /// + /// Allows a single call through, during which all other callers fail-fast. If the call fails, the breaker reopens. + /// If the call succeeds, the breaker closes. + /// + /// Implementation of the call that needs protected + /// containing result of protected call + [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter")] + public override Task Invoke(Func body) + { + CheckState(); + return CallThrough(body); } /// @@ -165,17 +222,24 @@ public override Task InvokeState(TState state, Func /// /// Implementation of the call that needs protected /// containing result of protected call - public override async Task Invoke(Func body) + public override Task Invoke(Func body) { CheckState(); - await CallThrough(body); + return CallThrough(body); } - public override async Task InvokeState(TState state, + [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter")] + public override Task InvokeState(TState state, Func body) { CheckState(); - await CallThrough(state,body); + return CallThrough(state, body); + } + + public override Task InvokeState(TState state, Func body) + { + CheckState(); + return CallThrough(state, body); } /// @@ -210,7 +274,7 @@ protected override void EnterInternal() /// TBD public override string ToString() { - return string.Format(CultureInfo.InvariantCulture, "Half-Open currently testing call for success = {0}", (_lock.Value == true)); + return $"Half-Open currently testing call for success = {_lock.Value}"; } } @@ -234,34 +298,69 @@ public Closed(CircuitBreaker breaker) /// /// Implementation of invoke, which simply attempts the call /// - /// TBD + /// The return value of the invoked function /// Implementation of the call that needs protected /// containing result of protected call + [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter")] public override Task Invoke(Func> body) { return CallThrough(body); } + /// + /// Implementation of invoke, which simply attempts the call + /// + /// The return value of the invoked function + /// Implementation of the call that needs protected + /// containing result of protected call + public override Task Invoke(Func> body) + { + return CallThrough(body); + } + + [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter")] public override Task InvokeState(TState state, Func> body) { return CallThrough(state, body); } + public override Task InvokeState(TState state, Func> body) + { + return CallThrough(state, body); + } + /// /// Implementation of invoke, which simply attempts the call /// /// Implementation of the call that needs protected /// containing result of protected call + [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter")] public override Task Invoke(Func body) { return CallThrough(body); } + /// + /// Implementation of invoke, which simply attempts the call + /// + /// Implementation of the call that needs protected + /// containing result of protected call + public override Task Invoke(Func body) + { + return CallThrough(body); + } + + [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter")] public override Task InvokeState(TState state, Func body) { return CallThrough(state, body); } + public override Task InvokeState(TState state, Func body) + { + return CallThrough(state, body); + } + /// /// On failed call, the failure count is incremented. The count is checked against the configured maxFailures, and /// the breaker is tripped if we have reached maxFailures. diff --git a/src/core/Akka/Util/Internal/AtomicState.cs b/src/core/Akka/Util/Internal/AtomicState.cs index 62145bfe94e..b9ce6de5b38 100644 --- a/src/core/Akka/Util/Internal/AtomicState.cs +++ b/src/core/Akka/Util/Internal/AtomicState.cs @@ -8,6 +8,7 @@ using System; using System.Collections.Concurrent; using System.Runtime.ExceptionServices; +using System.Threading; using System.Threading.Tasks; namespace Akka.Util.Internal @@ -94,6 +95,31 @@ public async Task CallThrough(Func> task) return result; } + /// + /// Shared implementation of call across all states. Thrown exception or execution of the call beyond the allowed + /// call timeout is counted as a failed call, otherwise a successful call + /// + /// Implementation of the call + /// containing the result of the call + public async Task CallThrough(Func> task) + { + var result = default(T); + try + { + using(var cts = new CancellationTokenSource(_callTimeout)) + result = await task(cts.Token).WaitAsync(cts.Token).ConfigureAwait(false); + CallSucceeds(); + } + catch (Exception ex) + { + var capturedException = ExceptionDispatchInfo.Capture(ex); + CallFails(capturedException.SourceException); + capturedException.Throw(); + } + + return result; + } + public async Task CallThrough(TState state, Func> task) { var result = default(T); @@ -112,8 +138,27 @@ public async Task CallThrough(TState state, Func> return result; } + public async Task CallThrough(TState state, Func> task) + { + var result = default(T); + try + { + using(var cts = new CancellationTokenSource(_callTimeout)) + result = await task(state, cts.Token).WaitAsync(cts.Token).ConfigureAwait(false); + CallSucceeds(); + } + catch (Exception ex) + { + var capturedException = ExceptionDispatchInfo.Capture(ex); + CallFails(capturedException.SourceException); + capturedException.Throw(); + } + + return result; + } + /// - /// Shared implementation of call across all states. Thrown exception or execution of the call beyond the allowed + /// Shared implementation of call across all states. Thrown exception or execution of the call beyond the allowed /// call timeout is counted as a failed call, otherwise a successful call /// /// Implementation of the call @@ -133,6 +178,28 @@ public async Task CallThrough(Func task) } } + /// + /// Shared implementation of call across all states. Thrown exception or execution of the call beyond the allowed + /// call timeout is counted as a failed call, otherwise a successful call + /// + /// Implementation of the call + /// containing the result of the call + public async Task CallThrough(Func task) + { + try + { + using(var cts = new CancellationTokenSource(_callTimeout)) + await task(cts.Token).WaitAsync(cts.Token).ConfigureAwait(false); + CallSucceeds(); + } + catch (Exception ex) + { + var capturedException = ExceptionDispatchInfo.Capture(ex); + CallFails(capturedException.SourceException); + capturedException.Throw(); + } + } + public async Task CallThrough(TState state, Func task) { try @@ -148,25 +215,94 @@ public async Task CallThrough(TState state, Func task) } } + public async Task CallThrough(TState state, Func task) + { + try + { + using(var cts = new CancellationTokenSource(_callTimeout)) + await task(state, cts.Token).WaitAsync(cts.Token).ConfigureAwait(false); + CallSucceeds(); + } + catch (Exception ex) + { + var capturedException = ExceptionDispatchInfo.Capture(ex); + CallFails(capturedException.SourceException); + capturedException.Throw(); + } + } + /// /// Abstract entry point for all states /// - /// TBD + /// The returned by the invoked function /// Implementation of the call that needs protected /// containing result of protected call + [Obsolete(message:"Use Invoke() that accepts functions with CancellationToken parameter")] public abstract Task Invoke(Func> body); + /// + /// Abstract entry point for all states + /// + /// The returned by the invoked function + /// Implementation of the call that needs protected + /// containing result of protected call + public abstract Task Invoke(Func> body); + + /// + /// Abstract entry point for all states + /// + /// The returned by the invoked function + /// The of the state object passed into the protected function + /// The state object will be passed into the protected function during invocation + /// Implementation of the call that needs protected + /// containing result of protected call + [Obsolete(message:"Use InvokeState() that accepts functions with CancellationToken parameter")] public abstract Task InvokeState(TState state, Func> body); /// /// Abstract entry point for all states /// + /// The returned by the invoked function + /// The of the state object passed into the protected function + /// The state object will be passed into the protected function during invocation /// Implementation of the call that needs protected /// containing result of protected call + public abstract Task InvokeState(TState state, Func> body); + + /// + /// Abstract entry point for all states + /// + /// Implementation of the call that needs protected + /// containing result of protected call + [Obsolete(message:"Use Invoke() that accepts functions with CancellationToken parameter")] public abstract Task Invoke(Func body); + /// + /// Abstract entry point for all states + /// + /// Implementation of the call that needs protected + /// containing result of protected call + public abstract Task Invoke(Func body); + + /// + /// Abstract entry point for all states + /// + /// The of the state object passed into the protected function + /// The state object will be passed into the protected function during invocation + /// Implementation of the call that needs protected + /// containing result of protected call + [Obsolete(message:"Use InvokeState() that accepts functions with CancellationToken parameter")] public abstract Task InvokeState(TState state, Func body); + /// + /// Abstract entry point for all states + /// + /// The of the state object passed into the protected function + /// The state object will be passed into the protected function during invocation + /// Implementation of the call that needs protected + /// containing result of protected call + public abstract Task InvokeState(TState state, Func body); + /// /// Invoked when call fails /// diff --git a/src/examples/Akka.Persistence.Custom/Journal/SqliteJournal.cs b/src/examples/Akka.Persistence.Custom/Journal/SqliteJournal.cs index 88b3b177b31..a4f9ee50ae2 100644 --- a/src/examples/Akka.Persistence.Custom/Journal/SqliteJournal.cs +++ b/src/examples/Akka.Persistence.Custom/Journal/SqliteJournal.cs @@ -273,12 +273,13 @@ public sealed override async Task ReplayMessagesAsync( // public sealed override async Task ReadHighestSequenceNrAsync( string persistenceId, - long fromSequenceNr) + long fromSequenceNr, + CancellationToken cancellationToken) { // Create a new DbConnection instance using (var connection = new SqliteConnection(_connectionString)) using (var cts = CancellationTokenSource - .CreateLinkedTokenSource(_pendingRequestsCancellation.Token)) + .CreateLinkedTokenSource(_pendingRequestsCancellation.Token, cancellationToken)) { await connection.OpenAsync(cts.Token); // Create new DbCommand instance @@ -299,7 +300,7 @@ public sealed override async Task ReadHighestSequenceNrAsync( // protected sealed override async Task> WriteMessagesAsync( - IEnumerable messages) + IEnumerable messages, CancellationToken cancellationToken) { // For each of the atomic write request, create an async Task var writeTasks = messages.Select(async message => @@ -307,7 +308,7 @@ protected sealed override async Task> WriteMessagesAsy // Create a new DbConnection instance using (var connection = new SqliteConnection(_connectionString)) using (var cts = CancellationTokenSource - .CreateLinkedTokenSource(_pendingRequestsCancellation.Token)) + .CreateLinkedTokenSource(_pendingRequestsCancellation.Token, cancellationToken)) { await connection.OpenAsync(cts.Token); @@ -384,7 +385,7 @@ protected sealed override async Task> WriteMessagesAsy .ContinueWhenAll(writeTasks, tasks => tasks.Select(t => t.IsFaulted ? TryUnwrapException(t.Exception) - : null).ToImmutableList()); + : null).ToImmutableList(), cancellationToken); return result; } @@ -393,15 +394,16 @@ protected sealed override async Task> WriteMessagesAsy // protected sealed override async Task DeleteMessagesToAsync( string persistenceId, - long toSequenceNr) + long toSequenceNr, + CancellationToken cancellationToken) { // Create a new DbConnection instance using (var connection = new SqliteConnection(_connectionString)) { - await connection.OpenAsync(); + await connection.OpenAsync(cancellationToken); using (var cts = CancellationTokenSource - .CreateLinkedTokenSource(_pendingRequestsCancellation.Token)) + .CreateLinkedTokenSource(_pendingRequestsCancellation.Token, cancellationToken)) { // We will be using two DbCommands to complete this process using (var deleteCommand = GetCommand(connection, DeleteBatchSql, _timeout)) diff --git a/src/examples/Akka.Persistence.Custom/Snapshot/SqliteSnapshotStore.cs b/src/examples/Akka.Persistence.Custom/Snapshot/SqliteSnapshotStore.cs index 11ec717b2c8..ab143f7e5a3 100644 --- a/src/examples/Akka.Persistence.Custom/Snapshot/SqliteSnapshotStore.cs +++ b/src/examples/Akka.Persistence.Custom/Snapshot/SqliteSnapshotStore.cs @@ -184,12 +184,13 @@ private bool WaitingForInitialization(object message) // protected sealed override async Task LoadAsync( string persistenceId, - SnapshotSelectionCriteria criteria) + SnapshotSelectionCriteria criteria, + CancellationToken cancellationToken) { // Create a new DbConnection instance using (var connection = new SqliteConnection(_connectionString)) using (var cts = CancellationTokenSource - .CreateLinkedTokenSource(_pendingRequestsCancellation.Token)) + .CreateLinkedTokenSource(_pendingRequestsCancellation.Token, cancellationToken)) { await connection.OpenAsync(cts.Token); @@ -234,12 +235,13 @@ protected sealed override async Task LoadAsync( // protected sealed override async Task SaveAsync( SnapshotMetadata metadata, - object snapshot) + object snapshot, + CancellationToken cancellationToken) { // Create a new DbConnection instance using (var connection = new SqliteConnection(_connectionString)) using (var cts = CancellationTokenSource - .CreateLinkedTokenSource(_pendingRequestsCancellation.Token)) + .CreateLinkedTokenSource(_pendingRequestsCancellation.Token, cancellationToken)) { await connection.OpenAsync(cts.Token); @@ -302,12 +304,12 @@ protected sealed override async Task SaveAsync( // // - protected sealed override async Task DeleteAsync(SnapshotMetadata metadata) + protected sealed override async Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { // Create a new DbConnection instance using (var connection = new SqliteConnection(_connectionString)) using (var cts = CancellationTokenSource - .CreateLinkedTokenSource(_pendingRequestsCancellation.Token)) + .CreateLinkedTokenSource(_pendingRequestsCancellation.Token, cancellationToken)) { await connection.OpenAsync(cts.Token); var timestamp = metadata.Timestamp != DateTime.MinValue @@ -346,12 +348,13 @@ protected sealed override async Task DeleteAsync(SnapshotMetadata metadata) // protected sealed override async Task DeleteAsync( string persistenceId, - SnapshotSelectionCriteria criteria) + SnapshotSelectionCriteria criteria, + CancellationToken cancellationToken) { // Create a new DbConnection instance using (var connection = new SqliteConnection(_connectionString)) using (var cts = CancellationTokenSource - .CreateLinkedTokenSource(_pendingRequestsCancellation.Token)) + .CreateLinkedTokenSource(_pendingRequestsCancellation.Token, cancellationToken)) { await connection.OpenAsync(cts.Token); From 46efbb3f1edb84525be979e92ac57327cf4b45fa Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Wed, 7 May 2025 05:26:15 +0700 Subject: [PATCH 02/11] Update API Approval list --- ...oreAPISpec.ApproveCore.DotNet.verified.txt | 8 +++ .../CoreAPISpec.ApproveCore.Net.verified.txt | 8 +++ ...pec.ApprovePersistence.DotNet.verified.txt | 52 +++++++++---------- ...PISpec.ApprovePersistence.Net.verified.txt | 52 +++++++++---------- 4 files changed, 68 insertions(+), 52 deletions(-) diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt index afc6e038e32..28ad4dc5570 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt @@ -4528,10 +4528,18 @@ namespace Akka.Pattern public Akka.Pattern.CircuitBreaker OnHalfOpen(System.Action callback) { } public Akka.Pattern.CircuitBreaker OnOpen(System.Action callback) { } public void Succeed() { } + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] public System.Threading.Tasks.Task WithCircuitBreaker(System.Func> body) { } + public System.Threading.Tasks.Task WithCircuitBreaker(System.Func> body) { } + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func> body) { } + public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func> body) { } + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] public System.Threading.Tasks.Task WithCircuitBreaker(System.Func body) { } + public System.Threading.Tasks.Task WithCircuitBreaker(System.Func body) { } + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func body) { } + public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func body) { } public Akka.Pattern.CircuitBreaker WithExponentialBackoff(System.TimeSpan maxResetTimeout) { } public Akka.Pattern.CircuitBreaker WithRandomFactor(double randomFactor) { } public void WithSyncCircuitBreaker(System.Action body) { } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt index 895d2bd5d76..7e81d96afca 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt @@ -4518,10 +4518,18 @@ namespace Akka.Pattern public Akka.Pattern.CircuitBreaker OnHalfOpen(System.Action callback) { } public Akka.Pattern.CircuitBreaker OnOpen(System.Action callback) { } public void Succeed() { } + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] public System.Threading.Tasks.Task WithCircuitBreaker(System.Func> body) { } + public System.Threading.Tasks.Task WithCircuitBreaker(System.Func> body) { } + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func> body) { } + public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func> body) { } + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] public System.Threading.Tasks.Task WithCircuitBreaker(System.Func body) { } + public System.Threading.Tasks.Task WithCircuitBreaker(System.Func body) { } + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func body) { } + public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func body) { } public Akka.Pattern.CircuitBreaker WithExponentialBackoff(System.TimeSpan maxResetTimeout) { } public Akka.Pattern.CircuitBreaker WithRandomFactor(double randomFactor) { } public void WithSyncCircuitBreaker(System.Action body) { } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.DotNet.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.DotNet.verified.txt index 844c2537500..d56d0a2edd9 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.DotNet.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.DotNet.verified.txt @@ -857,14 +857,14 @@ namespace Akka.Persistence.Journal { protected readonly bool CanPublish; protected AsyncWriteJournal() { } - protected abstract System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr); - public abstract System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); + protected abstract System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken); + public abstract System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken); protected virtual bool Receive(object message) { } protected virtual bool ReceivePluginInternal(object message) { } protected bool ReceiveWriteJournal(object message) { } public abstract System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback); protected static System.Exception TryUnwrapException(System.Exception e) { } - protected abstract System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages); + protected abstract System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken); } public abstract class AsyncWriteProxy : Akka.Persistence.Journal.AsyncWriteJournal, Akka.Actor.IActorStash, Akka.Actor.IWithUnboundedStash, Akka.Actor.IWithUnrestrictedStash, Akka.Dispatch.IRequiresMessageQueue { @@ -873,10 +873,10 @@ namespace Akka.Persistence.Journal public abstract System.TimeSpan Timeout { get; } public override void AroundPreStart() { } protected override bool AroundReceive(Akka.Actor.Receive receive, object message) { } - protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) { } - public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) { } + protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken) { } + public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken) { } public override System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback) { } - protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages) { } + protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken) { } public class InitTimeout { public static Akka.Persistence.Journal.AsyncWriteProxy.InitTimeout Instance { get; } @@ -957,7 +957,7 @@ namespace Akka.Persistence.Journal } public interface IAsyncRecovery { - System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); + System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken); System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback); } public interface IEmptyEventSequence : Akka.Persistence.Journal.IEventSequence { } @@ -988,14 +988,14 @@ namespace Akka.Persistence.Journal protected virtual System.Collections.Concurrent.ConcurrentDictionary> Messages { get; } public System.Collections.Generic.IDictionary> Add(Akka.Persistence.IPersistentRepresentation persistent) { } public System.Collections.Generic.IDictionary> Delete(string pid, long seqNr) { } - protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) { } + protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken) { } public long HighestSequenceNr(string pid) { } public System.Collections.Generic.IEnumerable Read(string pid, long fromSeqNr, long toSeqNr, long max) { } - public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) { } + public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken) { } protected override bool ReceivePluginInternal(object message) { } public override System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback) { } public System.Collections.Generic.IDictionary> Update(string pid, long seqNr, System.Func updater) { } - protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages) { } + protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken) { } public sealed class CurrentPersistenceIds : Akka.Event.IDeadLetterSuppression { public readonly System.Collections.Generic.IEnumerable AllPersistenceIds; @@ -1166,14 +1166,14 @@ namespace Akka.Persistence.Snapshot public class LocalSnapshotStore : Akka.Persistence.Snapshot.SnapshotStore { public LocalSnapshotStore() { } - protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } - protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } + protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } protected System.IO.FileInfo GetSnapshotFileForWrite(Akka.Persistence.SnapshotMetadata metadata, string extension = "") { } - protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } + protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } protected override void PreStart() { } protected override bool ReceivePluginInternal(object message) { } protected virtual void Save(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } - protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } + protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } protected void Serialize(System.IO.Stream stream, Akka.Persistence.Serialization.Snapshot snapshot) { } protected System.IO.FileInfo WithOutputStream(Akka.Persistence.SnapshotMetadata metadata, System.Action p) { } } @@ -1181,18 +1181,18 @@ namespace Akka.Persistence.Snapshot { public MemorySnapshotStore() { } protected virtual System.Collections.Generic.List Snapshots { get; } - protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } - protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } - protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } - protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } + protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } } public sealed class NoSnapshotStore : Akka.Persistence.Snapshot.SnapshotStore { public NoSnapshotStore() { } - protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } - protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } - protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } - protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } + protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } public class NoSnapshotStoreException : System.Exception { public NoSnapshotStoreException() { } @@ -1213,11 +1213,11 @@ namespace Akka.Persistence.Snapshot public abstract class SnapshotStore : Akka.Actor.ActorBase { protected SnapshotStore() { } - protected abstract System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata); - protected abstract System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria); - protected abstract System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria); + protected abstract System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken); + protected abstract System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken); + protected abstract System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken); protected virtual bool Receive(object message) { } protected virtual bool ReceivePluginInternal(object message) { } - protected abstract System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot); + protected abstract System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.Net.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.Net.verified.txt index 72f9b83e453..a136e19d3d9 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.Net.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.Net.verified.txt @@ -857,14 +857,14 @@ namespace Akka.Persistence.Journal { protected readonly bool CanPublish; protected AsyncWriteJournal() { } - protected abstract System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr); - public abstract System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); + protected abstract System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken); + public abstract System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken); protected virtual bool Receive(object message) { } protected virtual bool ReceivePluginInternal(object message) { } protected bool ReceiveWriteJournal(object message) { } public abstract System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback); protected static System.Exception TryUnwrapException(System.Exception e) { } - protected abstract System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages); + protected abstract System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken); } public abstract class AsyncWriteProxy : Akka.Persistence.Journal.AsyncWriteJournal, Akka.Actor.IActorStash, Akka.Actor.IWithUnboundedStash, Akka.Actor.IWithUnrestrictedStash, Akka.Dispatch.IRequiresMessageQueue { @@ -873,10 +873,10 @@ namespace Akka.Persistence.Journal public abstract System.TimeSpan Timeout { get; } public override void AroundPreStart() { } protected override bool AroundReceive(Akka.Actor.Receive receive, object message) { } - protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) { } - public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) { } + protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken) { } + public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken) { } public override System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback) { } - protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages) { } + protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken) { } public class InitTimeout { public static Akka.Persistence.Journal.AsyncWriteProxy.InitTimeout Instance { get; } @@ -957,7 +957,7 @@ namespace Akka.Persistence.Journal } public interface IAsyncRecovery { - System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); + System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken); System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback); } public interface IEmptyEventSequence : Akka.Persistence.Journal.IEventSequence { } @@ -988,14 +988,14 @@ namespace Akka.Persistence.Journal protected virtual System.Collections.Concurrent.ConcurrentDictionary> Messages { get; } public System.Collections.Generic.IDictionary> Add(Akka.Persistence.IPersistentRepresentation persistent) { } public System.Collections.Generic.IDictionary> Delete(string pid, long seqNr) { } - protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) { } + protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken) { } public long HighestSequenceNr(string pid) { } public System.Collections.Generic.IEnumerable Read(string pid, long fromSeqNr, long toSeqNr, long max) { } - public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) { } + public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken) { } protected override bool ReceivePluginInternal(object message) { } public override System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback) { } public System.Collections.Generic.IDictionary> Update(string pid, long seqNr, System.Func updater) { } - protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages) { } + protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken) { } public sealed class CurrentPersistenceIds : Akka.Event.IDeadLetterSuppression { public readonly System.Collections.Generic.IEnumerable AllPersistenceIds; @@ -1164,14 +1164,14 @@ namespace Akka.Persistence.Snapshot public class LocalSnapshotStore : Akka.Persistence.Snapshot.SnapshotStore { public LocalSnapshotStore() { } - protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } - protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } + protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } protected System.IO.FileInfo GetSnapshotFileForWrite(Akka.Persistence.SnapshotMetadata metadata, string extension = "") { } - protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } + protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } protected override void PreStart() { } protected override bool ReceivePluginInternal(object message) { } protected virtual void Save(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } - protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } + protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } protected void Serialize(System.IO.Stream stream, Akka.Persistence.Serialization.Snapshot snapshot) { } protected System.IO.FileInfo WithOutputStream(Akka.Persistence.SnapshotMetadata metadata, System.Action p) { } } @@ -1179,18 +1179,18 @@ namespace Akka.Persistence.Snapshot { public MemorySnapshotStore() { } protected virtual System.Collections.Generic.List Snapshots { get; } - protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } - protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } - protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } - protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } + protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } } public sealed class NoSnapshotStore : Akka.Persistence.Snapshot.SnapshotStore { public NoSnapshotStore() { } - protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } - protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } - protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } - protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } + protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } public class NoSnapshotStoreException : System.Exception { public NoSnapshotStoreException() { } @@ -1211,11 +1211,11 @@ namespace Akka.Persistence.Snapshot public abstract class SnapshotStore : Akka.Actor.ActorBase { protected SnapshotStore() { } - protected abstract System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata); - protected abstract System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria); - protected abstract System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria); + protected abstract System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken); + protected abstract System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken); + protected abstract System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken); protected virtual bool Receive(object message) { } protected virtual bool ReceivePluginInternal(object message) { } - protected abstract System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot); + protected abstract System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken); } } \ No newline at end of file From 72589eb92b93556964ad13b5503e6a56eef585c3 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Wed, 7 May 2025 21:37:19 +0700 Subject: [PATCH 03/11] Unify TaskCancelledException to TimeoutException (old behavior) --- .../Pattern/CircuitBreakerStressSpec.cs | 4 ++-- src/core/Akka/Util/Internal/AtomicState.cs | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/core/Akka.Tests/Pattern/CircuitBreakerStressSpec.cs b/src/core/Akka.Tests/Pattern/CircuitBreakerStressSpec.cs index b23a8ed3c3a..7007ca5b4e6 100644 --- a/src/core/Akka.Tests/Pattern/CircuitBreakerStressSpec.cs +++ b/src/core/Akka.Tests/Pattern/CircuitBreakerStressSpec.cs @@ -125,10 +125,10 @@ public async Task A_CircuitBreaker_stress_test() { stressActor.Tell(GetResult.Instance); var result = ExpectMsg(); - result.FailCount.ShouldBe(0); - Output.WriteLine("FailCount:{0}, DoneCount:{1}, CircCount:{2}, TimeoutCount:{3}", result.FailCount, result.DoneCount, result.CircCount, result.TimeoutCount); + + result.FailCount.ShouldBe(0); } } } diff --git a/src/core/Akka/Util/Internal/AtomicState.cs b/src/core/Akka/Util/Internal/AtomicState.cs index b9ce6de5b38..d754c11365a 100644 --- a/src/core/Akka/Util/Internal/AtomicState.cs +++ b/src/core/Akka/Util/Internal/AtomicState.cs @@ -87,6 +87,8 @@ public async Task CallThrough(Func> task) } catch (Exception ex) { + if (ex is TaskCanceledException) + ex = new TimeoutException("Task was cancelled, probably because of a timeout", ex); var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); @@ -112,6 +114,8 @@ public async Task CallThrough(Func> task) } catch (Exception ex) { + if (ex is TaskCanceledException) + ex = new TimeoutException("Task was cancelled, probably because of a timeout", ex); var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); @@ -130,6 +134,8 @@ public async Task CallThrough(TState state, Func> } catch (Exception ex) { + if (ex is TaskCanceledException) + ex = new TimeoutException("Task was cancelled, probably because of a timeout", ex); var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); @@ -149,6 +155,8 @@ public async Task CallThrough(TState state, Func task) } catch (Exception ex) { + if (ex is TaskCanceledException) + ex = new TimeoutException("Task was cancelled, probably because of a timeout", ex); var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); @@ -194,6 +204,8 @@ public async Task CallThrough(Func task) } catch (Exception ex) { + if (ex is TaskCanceledException) + ex = new TimeoutException("Task was cancelled, probably because of a timeout", ex); var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); @@ -209,6 +221,8 @@ public async Task CallThrough(TState state, Func task) } catch (Exception ex) { + if (ex is TaskCanceledException) + ex = new TimeoutException("Task was cancelled, probably because of a timeout", ex); var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); @@ -225,6 +239,8 @@ public async Task CallThrough(TState state, Func Date: Thu, 8 May 2025 03:18:51 +0700 Subject: [PATCH 04/11] Make Akka.Persistence API changes backward compatible --- .../AsyncWriteProxyEx.cs | 12 ++- .../SnapshotStoreProxy.cs | 16 ++++ .../Bugfix7399Specs.cs | 16 ++++ .../Journal/ChaosJournal.cs | 12 +++ .../Akka.Persistence/Journal/AsyncRecovery.cs | 22 +++++ .../Journal/AsyncWriteJournal.cs | 87 +++++++++++++++++++ .../Akka.Persistence/Journal/MemoryJournal.cs | 9 ++ .../Snapshot/LocalSnapshotStore.cs | 16 ++++ .../Snapshot/MemorySnapshotStore.cs | 16 ++++ .../Snapshot/NoSnapshotStore.cs | 24 +++++ .../Snapshot/SnapshotStore.cs | 45 ++++++++++ src/core/Akka/Pattern/CircuitBreaker.cs | 8 +- src/core/Akka/Pattern/CircuitBreakerState.cs | 24 ++--- src/core/Akka/Util/Internal/AtomicState.cs | 8 +- .../Journal/SqliteJournal.cs | 12 +++ .../Snapshot/SqliteSnapshotStore.cs | 16 ++++ 16 files changed, 322 insertions(+), 21 deletions(-) diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/AsyncWriteProxyEx.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/AsyncWriteProxyEx.cs index c47098fa349..6d9def40ca2 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/AsyncWriteProxyEx.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/AsyncWriteProxyEx.cs @@ -156,7 +156,9 @@ protected internal override bool AroundReceive(Receive receive, object message) return true; } - + [Obsolete("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task> WriteMessagesAsync(IEnumerable messages) + => WriteMessagesAsync(messages, CancellationToken.None); protected override Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { @@ -182,6 +184,10 @@ protected override Task> WriteMessagesAsync(IEnumerabl }, TaskContinuationOptions.ExecuteSynchronously); } + [Obsolete("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) + => DeleteMessagesToAsync(persistenceId, toSequenceNr, CancellationToken.None); + protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, CancellationToken cancellationToken) { if (_store == null) @@ -229,6 +235,10 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten return replayCompletionPromise.Task; } + [Obsolete("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) + => ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr, CancellationToken.None); + public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken) { if (_store == null) diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs index 2c8a4d98d5f..60484ac3b50 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs @@ -90,6 +90,10 @@ protected internal override bool AroundReceive(Receive receive, object message) return true; } + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteAsync(SnapshotMetadata metadata) + => DeleteAsync(metadata, CancellationToken.None); + protected override async Task DeleteAsync( SnapshotMetadata metadata, CancellationToken cancellationToken) @@ -112,6 +116,10 @@ protected override async Task DeleteAsync( } } + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + => DeleteAsync(persistenceId, criteria, CancellationToken.None); + protected override async Task DeleteAsync( string persistenceId, SnapshotSelectionCriteria criteria, @@ -135,6 +143,10 @@ protected override async Task DeleteAsync( } } + [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) + => LoadAsync(persistenceId, criteria, CancellationToken.None); + protected override async Task LoadAsync( string persistenceId, SnapshotSelectionCriteria criteria, @@ -166,6 +178,10 @@ protected override async Task LoadAsync( throw new TimeoutException(); } + [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) + => SaveAsync(metadata, snapshot, CancellationToken.None); + protected override async Task SaveAsync( SnapshotMetadata metadata, object snapshot, diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/Bugfix7399Specs.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/Bugfix7399Specs.cs index 5c62adf13db..4880358f7d2 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/Bugfix7399Specs.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/Bugfix7399Specs.cs @@ -166,6 +166,10 @@ public class FailingSnapshot : SnapshotStore { public static bool Working = false; + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteAsync(SnapshotMetadata metadata) + => DeleteAsync(metadata, CancellationToken.None); + protected override Task DeleteAsync( SnapshotMetadata metadata, CancellationToken cancellationToken) @@ -178,6 +182,10 @@ protected override Task DeleteAsync( return Task.CompletedTask; } + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + => DeleteAsync(persistenceId, criteria, CancellationToken.None); + protected override Task DeleteAsync( string persistenceId, SnapshotSelectionCriteria criteria, @@ -191,6 +199,10 @@ protected override Task DeleteAsync( return Task.CompletedTask; } + [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) + => LoadAsync(persistenceId, criteria, CancellationToken.None); + protected override async Task LoadAsync( string persistenceId, SnapshotSelectionCriteria criteria, @@ -204,6 +216,10 @@ protected override async Task LoadAsync( return null; } + [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) + => SaveAsync(metadata, snapshot, CancellationToken.None); + protected override Task SaveAsync( SnapshotMetadata metadata, object snapshot, diff --git a/src/core/Akka.Persistence.Tests/Journal/ChaosJournal.cs b/src/core/Akka.Persistence.Tests/Journal/ChaosJournal.cs index c2ba8de4af4..c94bcd50536 100644 --- a/src/core/Akka.Persistence.Tests/Journal/ChaosJournal.cs +++ b/src/core/Akka.Persistence.Tests/Journal/ChaosJournal.cs @@ -84,6 +84,10 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten return promise.Task; } + [Obsolete("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) + => ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr, CancellationToken.None); + public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken) { var promise = new TaskCompletionSource(); @@ -94,6 +98,10 @@ public override Task ReadHighestSequenceNrAsync(string persistenceId, long return promise.Task; } + [Obsolete("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task> WriteMessagesAsync(IEnumerable messages) + => WriteMessagesAsync(messages, CancellationToken.None); + protected override Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { var promise = @@ -121,6 +129,10 @@ protected override Task> WriteMessagesAsync(IEnumerabl return promise.Task; } + [Obsolete("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) + => DeleteMessagesToAsync(persistenceId, toSequenceNr, CancellationToken.None); + protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, CancellationToken cancellationToken) { TaskCompletionSource promise = new TaskCompletionSource(); diff --git a/src/core/Akka.Persistence/Journal/AsyncRecovery.cs b/src/core/Akka.Persistence/Journal/AsyncRecovery.cs index b88562b2908..86bc81ad665 100644 --- a/src/core/Akka.Persistence/Journal/AsyncRecovery.cs +++ b/src/core/Akka.Persistence/Journal/AsyncRecovery.cs @@ -45,6 +45,28 @@ public interface IAsyncRecovery /// TBD Task ReplayMessagesAsync(IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, Action recoveryCallback); + /// + /// Asynchronously reads the highest stored sequence number for provided . + /// The persistent actor will use the highest sequence number after recovery as the starting point when + /// persisting new events. + /// This sequence number is also used as `toSequenceNr` in subsequent calls to + /// unless the user has specified a lower `toSequenceNr`. + /// Journal must maintain the highest sequence number and never decrease it. + /// + /// This call is protected with a circuit-breaker. + /// + /// Please also not that requests for the highest sequence number may be made concurrently + /// to writes executing for the same , in particular it is + /// possible that a restarting actor tries to recover before its outstanding writes have completed. + /// + /// Persistent actor identifier + /// Hint where to start searching for the highest sequence number. + /// When a persistent actor is recovering this will the sequence + /// number of the used snapshot, or `0L` if no snapshot is used. + /// TBD + [Obsolete("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); + /// /// Asynchronously reads the highest stored sequence number for provided . /// The persistent actor will use the highest sequence number after recovery as the starting point when diff --git a/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs b/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs index 0d8a8b2b21d..fbfa69caa53 100644 --- a/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs +++ b/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs @@ -89,9 +89,87 @@ protected AsyncWriteJournal() /// public abstract Task ReplayMessagesAsync(IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, Action recoveryCallback); + /// + [Obsolete("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + public abstract Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); + /// public abstract Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken); + /// + /// Plugin API: asynchronously writes a batch of persistent messages to the + /// journal. + /// + /// The batch is only for performance reasons, i.e. all messages don't have to be written + /// atomically. Higher throughput can typically be achieved by using batch inserts of many + /// records compared to inserting records one-by-one, but this aspect depends on the + /// underlying data store and a journal implementation can implement it as efficient as + /// possible. Journals should aim to persist events in-order for a given `persistenceId` + /// as otherwise in case of a failure, the persistent state may be end up being inconsistent. + /// + /// Each message contains the single + /// that corresponds to the event that was passed to the + /// method of the + /// , or it contains several + /// that correspond to the events that were passed to the + /// + /// method of the . All of the + /// must be written to the data store atomically, i.e. all or none must + /// be stored. If the journal (data store) cannot support atomic writes of multiple + /// events it should reject such writes with a + /// describing the issue. This limitation should also be documented by the journal plugin. + /// + /// If there are failures when storing any of the messages in the batch the returned + /// must be completed with failure. The must only be completed with + /// success when all messages in the batch have been confirmed to be stored successfully, + /// i.e. they will be readable, and visible, in a subsequent replay. If there is + /// uncertainty about if the messages were stored or not the must be completed + /// with failure. + /// + /// Data store connection problems must be signaled by completing the with + /// failure. + /// + /// The journal can also signal that it rejects individual messages () by + /// the returned . It is possible but not mandatory to reduce + /// number of allocations by returning null for the happy path, + /// i.e. when no messages are rejected. Otherwise the returned list must have as many elements + /// as the input . Each result element signals if the corresponding + /// is rejected or not, with an exception describing the problem. Rejecting + /// a message means it was not stored, i.e. it must not be included in a later replay. + /// Rejecting a message is typically done before attempting to store it, e.g. because of + /// serialization error. + /// + /// Data store connection problems must not be signaled as rejections. + /// + /// It is possible but not mandatory to reduce number of allocations by returning + /// null for the happy path, i.e. when no messages are rejected. + /// + /// Calls to this method are serialized by the enclosing journal actor. If you spawn + /// work in asynchronous tasks it is alright that they complete the futures in any order, + /// but the actual writes for a specific persistenceId should be serialized to avoid + /// issues such as events of a later write are visible to consumers (query side, or replay) + /// before the events of an earlier write are visible. + /// A will not send a new request before + /// the previous one has been completed. + /// + /// Please not that the of the contained + /// objects has been nulled out (i.e. set to + /// in order to not use space in the journal for a sender reference that will likely be obsolete + /// during replay. + /// + /// Please also note that requests for the highest sequence number may be made concurrently + /// to this call executing for the same `persistenceId`, in particular it is possible that + /// a restarting actor tries to recover before its outstanding writes have completed. + /// In the latter case it is highly desirable to defer reading the highest sequence number + /// until all outstanding writes have completed, otherwise the + /// may reuse sequence numbers. + /// + /// This call is protected with a circuit-breaker. + /// + /// TBD + [Obsolete("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract Task> WriteMessagesAsync(IEnumerable messages); + /// /// Plugin API: asynchronously writes a batch of persistent messages to the /// journal. @@ -166,6 +244,15 @@ protected AsyncWriteJournal() /// used to signal cancelled snapshot operation protected abstract Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken); + /// + /// Asynchronously deletes all persistent messages up to inclusive + /// bound. + /// + /// TBD + /// TBD + [Obsolete("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr); + /// /// Asynchronously deletes all persistent messages up to inclusive /// bound. diff --git a/src/core/Akka.Persistence/Journal/MemoryJournal.cs b/src/core/Akka.Persistence/Journal/MemoryJournal.cs index d335d42d300..a6f516139d6 100644 --- a/src/core/Akka.Persistence/Journal/MemoryJournal.cs +++ b/src/core/Akka.Persistence/Journal/MemoryJournal.cs @@ -32,6 +32,9 @@ public class MemoryJournal : AsyncWriteJournal protected virtual ConcurrentDictionary> Messages { get { return _messages; } } + protected override Task> WriteMessagesAsync(IEnumerable messages) + => WriteMessagesAsync(messages, CancellationToken.None); + protected override Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { foreach (var w in messages) @@ -59,6 +62,9 @@ protected override Task> WriteMessagesAsync(IEnumerabl return Task.FromResult>(null); // all good } + + public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) + => ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr, CancellationToken.None); public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken) { @@ -74,6 +80,9 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten return Task.CompletedTask; } + protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) + => DeleteMessagesToAsync(persistenceId, toSequenceNr, CancellationToken.None); + protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, CancellationToken cancellationToken) { var highestSeqNr = HighestSequenceNr(persistenceId); diff --git a/src/core/Akka.Persistence/Snapshot/LocalSnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/LocalSnapshotStore.cs index 9c1d8196c2c..6044c7b29ca 100644 --- a/src/core/Akka.Persistence/Snapshot/LocalSnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/LocalSnapshotStore.cs @@ -67,6 +67,10 @@ public LocalSnapshotStore() private readonly ILoggingAdapter _log; + [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) + => LoadAsync(persistenceId, criteria, CancellationToken.None); + /// protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { @@ -81,6 +85,10 @@ protected override Task LoadAsync(string persistenceId, Snapsh return RunWithStreamDispatcher(() => Load(metadata)); } + [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) + => SaveAsync(metadata, snapshot, CancellationToken.None); + /// protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot, CancellationToken cancellationToken) { @@ -92,6 +100,10 @@ protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot, Ca }); } + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteAsync(SnapshotMetadata metadata) + => DeleteAsync(metadata, CancellationToken.None); + /// protected override Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { @@ -109,6 +121,10 @@ protected override Task DeleteAsync(SnapshotMetadata metadata, CancellationToken }); } + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + => DeleteAsync(persistenceId, criteria, CancellationToken.None); + /// protected override async Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { diff --git a/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs index 3664ecdeab3..f53cebabb77 100644 --- a/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs @@ -27,6 +27,10 @@ public class MemorySnapshotStore : SnapshotStore /// protected virtual List Snapshots { get; } = new(); + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteAsync(SnapshotMetadata metadata) + => DeleteAsync(metadata, CancellationToken.None); + protected override Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { var snapshot = Snapshots.FirstOrDefault(Pred); @@ -40,6 +44,10 @@ bool Pred(SnapshotEntry x) => && (metadata.Timestamp == DateTime.MinValue || metadata.Timestamp == DateTime.MaxValue || x.Timestamp == metadata.Timestamp.Ticks); } + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + => DeleteAsync(persistenceId, criteria, CancellationToken.None); + protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { var filter = CreateRangeFilter(persistenceId, criteria); @@ -48,6 +56,10 @@ protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCrite return TaskEx.Completed; } + [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) + => LoadAsync(persistenceId, criteria, CancellationToken.None); + protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { var filter = CreateRangeFilter(persistenceId, criteria); @@ -57,6 +69,10 @@ protected override Task LoadAsync(string persistenceId, Snapsh return Task.FromResult(snapshot); } + [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) + => SaveAsync(metadata, snapshot, CancellationToken.None); + protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot, CancellationToken cancellationToken) { diff --git a/src/core/Akka.Persistence/Snapshot/NoSnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/NoSnapshotStore.cs index 7f66b3ecbc3..91a54484ace 100644 --- a/src/core/Akka.Persistence/Snapshot/NoSnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/NoSnapshotStore.cs @@ -61,11 +61,23 @@ protected NoSnapshotStoreException(SerializationInfo info, StreamingContext cont } } + [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) + { + return Task.FromResult((SelectedSnapshot)null); + } + protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { return Task.FromResult((SelectedSnapshot)null); } + [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) + { + return Flop(); + } + /// /// This exception is thrown when no snapshot store is configured. /// @@ -74,6 +86,12 @@ protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot, Ca return Flop(); } + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteAsync(SnapshotMetadata metadata) + { + return Flop(); + } + /// /// This exception is thrown when no snapshot store is configured. /// @@ -82,6 +100,12 @@ protected override Task DeleteAsync(SnapshotMetadata metadata, CancellationToken return Flop(); } + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + { + return Flop(); + } + /// /// This exception is thrown when no snapshot store is configured. /// diff --git a/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs index 645f7e7f776..5955c4afde2 100644 --- a/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs @@ -271,6 +271,18 @@ private static Exception TryUnwrapException(Exception e) return e; } + /// + /// Plugin API: Asynchronously loads a snapshot. + /// + /// This call is protected with a circuit-breaker + /// + /// Id of the persistent actor. + /// Selection criteria for loading. + [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract Task LoadAsync( + string persistenceId, + SnapshotSelectionCriteria criteria); + /// /// Plugin API: Asynchronously loads a snapshot. /// @@ -284,6 +296,18 @@ protected abstract Task LoadAsync( SnapshotSelectionCriteria criteria, CancellationToken cancellationToken); + /// + /// Plugin API: Asynchronously saves a snapshot. + /// + /// This call is protected with a circuit-breaker + /// + /// Snapshot metadata. + /// Snapshot. + [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract Task SaveAsync( + SnapshotMetadata metadata, + object snapshot); + /// /// Plugin API: Asynchronously saves a snapshot. /// @@ -297,6 +321,15 @@ protected abstract Task SaveAsync( object snapshot, CancellationToken cancellationToken); + /// + /// Plugin API: Deletes the snapshot identified by . + /// + /// This call is protected with a circuit-breaker + /// + /// Snapshot metadata. + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract Task DeleteAsync(SnapshotMetadata metadata); + /// /// Plugin API: Deletes the snapshot identified by . /// @@ -306,6 +339,18 @@ protected abstract Task SaveAsync( /// used to signal cancelled snapshot operation protected abstract Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken); + /// + /// Plugin API: Deletes all snapshots matching provided . + /// + /// This call is protected with a circuit-breaker + /// + /// Id of the persistent actor. + /// Selection criteria for deleting. + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract Task DeleteAsync( + string persistenceId, + SnapshotSelectionCriteria criteria); + /// /// Plugin API: Deletes all snapshots matching provided . /// diff --git a/src/core/Akka/Pattern/CircuitBreaker.cs b/src/core/Akka/Pattern/CircuitBreaker.cs index df87ea0135c..c38f3b12711 100644 --- a/src/core/Akka/Pattern/CircuitBreaker.cs +++ b/src/core/Akka/Pattern/CircuitBreaker.cs @@ -223,7 +223,7 @@ public CircuitBreaker(IScheduler scheduler, int maxFailures, TimeSpan callTimeou /// The returned by the protected function /// Call needing protected /// containing the call result - [Obsolete(message:"Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] + [Obsolete(message:"Use WithCircuitBreaker() that accepts functions with CancellationToken parameter. Since 1.5.42")] public Task WithCircuitBreaker(Func> body) => CurrentState.Invoke(body); /// @@ -242,7 +242,7 @@ public CircuitBreaker(IScheduler scheduler, int maxFailures, TimeSpan callTimeou /// The state object will be passed into the protected function during invocation /// Call needing protected /// containing the call result - [Obsolete(message:"Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] + [Obsolete(message:"Use WithCircuitBreaker() that accepts functions with CancellationToken parameter. Since 1.5.42")] public Task WithCircuitBreaker(TState state, Func> body) => CurrentState.InvokeState(state, body); @@ -262,7 +262,7 @@ public Task WithCircuitBreaker(TState state, Func /// Call needing protected /// containing the call result - [Obsolete(message:"Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] + [Obsolete(message:"Use WithCircuitBreaker() that accepts functions with CancellationToken parameter. Since 1.5.42")] public Task WithCircuitBreaker(Func body) => CurrentState.Invoke(body); /// @@ -279,7 +279,7 @@ public Task WithCircuitBreaker(TState state, FuncThe state object will be passed into the protected function during invocation /// Call needing protected /// containing the call result - [Obsolete(message:"Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] + [Obsolete(message:"Use WithCircuitBreaker() that accepts functions with CancellationToken parameter. Since 1.5.42")] public Task WithCircuitBreaker(TState state, Func body) => CurrentState.InvokeState(state, body); diff --git a/src/core/Akka/Pattern/CircuitBreakerState.cs b/src/core/Akka/Pattern/CircuitBreakerState.cs index bafd2ea9d33..31bab3dcbbf 100644 --- a/src/core/Akka/Pattern/CircuitBreakerState.cs +++ b/src/core/Akka/Pattern/CircuitBreakerState.cs @@ -49,7 +49,7 @@ private TimeSpan RemainingDuration() /// The return value of the invoked function /// Implementation of the call that needs protected /// containing result of protected call - [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter")] + [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter. Since 1.5.42")] public override Task Invoke(Func> body) => Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); @@ -62,14 +62,14 @@ public override Task Invoke(Func> body) => public override Task Invoke(Func> body) => Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); - [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter")] + [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter. Since 1.5.42")] public override Task InvokeState(TState state, Func body) => Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); public override Task InvokeState(TState state, Func body) => Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); - [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter")] + [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter. Since 1.5.42")] public override Task InvokeState(TState state, Func> body) => Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); @@ -81,7 +81,7 @@ public override Task InvokeState(TState state, Func /// Implementation of the call that needs protected /// containing result of protected call - [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter")] + [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter. Since 1.5.42")] public override Task Invoke(Func body) => Task.FromException(new OpenCircuitException(_breaker.LastCaughtException, RemainingDuration())); @@ -170,7 +170,7 @@ private void CheckState() /// The return value of the invoked function /// Implementation of the call that needs protected /// containing result of protected call - [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter")] + [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter. Since 1.5.42")] public override Task Invoke(Func> body) { CheckState(); @@ -190,7 +190,7 @@ public override Task Invoke(Func> body) return CallThrough(body); } - [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter")] + [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter. Since 1.5.42")] public override Task InvokeState(TState state, Func> body) { CheckState(); @@ -209,7 +209,7 @@ public override Task InvokeState(TState state, Func /// Implementation of the call that needs protected /// containing result of protected call - [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter")] + [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter. Since 1.5.42")] public override Task Invoke(Func body) { CheckState(); @@ -228,7 +228,7 @@ public override Task Invoke(Func body) return CallThrough(body); } - [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter")] + [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter. Since 1.5.42")] public override Task InvokeState(TState state, Func body) { @@ -301,7 +301,7 @@ public Closed(CircuitBreaker breaker) /// The return value of the invoked function /// Implementation of the call that needs protected /// containing result of protected call - [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter")] + [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter. Since 1.5.42")] public override Task Invoke(Func> body) { return CallThrough(body); @@ -318,7 +318,7 @@ public override Task Invoke(Func> body) return CallThrough(body); } - [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter")] + [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter. Since 1.5.42")] public override Task InvokeState(TState state, Func> body) { return CallThrough(state, body); @@ -334,7 +334,7 @@ public override Task InvokeState(TState state, Func /// Implementation of the call that needs protected /// containing result of protected call - [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter")] + [Obsolete("Use Invoke() that accepts functions with CancellationToken parameter. Since 1.5.42")] public override Task Invoke(Func body) { return CallThrough(body); @@ -350,7 +350,7 @@ public override Task Invoke(Func body) return CallThrough(body); } - [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter")] + [Obsolete("Use InvokeState() that accepts functions with CancellationToken parameter. Since 1.5.42")] public override Task InvokeState(TState state, Func body) { return CallThrough(state, body); diff --git a/src/core/Akka/Util/Internal/AtomicState.cs b/src/core/Akka/Util/Internal/AtomicState.cs index d754c11365a..978ec84e2d9 100644 --- a/src/core/Akka/Util/Internal/AtomicState.cs +++ b/src/core/Akka/Util/Internal/AtomicState.cs @@ -253,7 +253,7 @@ public async Task CallThrough(TState state, FuncThe returned by the invoked function /// Implementation of the call that needs protected /// containing result of protected call - [Obsolete(message:"Use Invoke() that accepts functions with CancellationToken parameter")] + [Obsolete(message:"Use Invoke() that accepts functions with CancellationToken parameter. Since 1.5.42")] public abstract Task Invoke(Func> body); /// @@ -272,7 +272,7 @@ public async Task CallThrough(TState state, FuncThe state object will be passed into the protected function during invocation /// Implementation of the call that needs protected /// containing result of protected call - [Obsolete(message:"Use InvokeState() that accepts functions with CancellationToken parameter")] + [Obsolete(message:"Use InvokeState() that accepts functions with CancellationToken parameter. Since 1.5.42")] public abstract Task InvokeState(TState state, Func> body); /// @@ -290,7 +290,7 @@ public async Task CallThrough(TState state, Func /// Implementation of the call that needs protected /// containing result of protected call - [Obsolete(message:"Use Invoke() that accepts functions with CancellationToken parameter")] + [Obsolete(message:"Use Invoke() that accepts functions with CancellationToken parameter. Since 1.5.42")] public abstract Task Invoke(Func body); /// @@ -307,7 +307,7 @@ public async Task CallThrough(TState state, FuncThe state object will be passed into the protected function during invocation /// Implementation of the call that needs protected /// containing result of protected call - [Obsolete(message:"Use InvokeState() that accepts functions with CancellationToken parameter")] + [Obsolete(message:"Use InvokeState() that accepts functions with CancellationToken parameter. Since 1.5.42")] public abstract Task InvokeState(TState state, Func body); /// diff --git a/src/examples/Akka.Persistence.Custom/Journal/SqliteJournal.cs b/src/examples/Akka.Persistence.Custom/Journal/SqliteJournal.cs index a4f9ee50ae2..66d5b14c3e9 100644 --- a/src/examples/Akka.Persistence.Custom/Journal/SqliteJournal.cs +++ b/src/examples/Akka.Persistence.Custom/Journal/SqliteJournal.cs @@ -270,6 +270,10 @@ public sealed override async Task ReplayMessagesAsync( } // + [Obsolete("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + public sealed override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) + => ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr, CancellationToken.None); + // public sealed override async Task ReadHighestSequenceNrAsync( string persistenceId, @@ -298,6 +302,10 @@ public sealed override async Task ReadHighestSequenceNrAsync( } // + [Obsolete("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected sealed override async Task> WriteMessagesAsync(IEnumerable messages) + => await WriteMessagesAsync(messages, CancellationToken.None); + // protected sealed override async Task> WriteMessagesAsync( IEnumerable messages, CancellationToken cancellationToken) @@ -391,6 +399,10 @@ protected sealed override async Task> WriteMessagesAsy } // + [Obsolete("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected sealed override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) + => DeleteMessagesToAsync(persistenceId, toSequenceNr, CancellationToken.None); + // protected sealed override async Task DeleteMessagesToAsync( string persistenceId, diff --git a/src/examples/Akka.Persistence.Custom/Snapshot/SqliteSnapshotStore.cs b/src/examples/Akka.Persistence.Custom/Snapshot/SqliteSnapshotStore.cs index ab143f7e5a3..f50c8d769f2 100644 --- a/src/examples/Akka.Persistence.Custom/Snapshot/SqliteSnapshotStore.cs +++ b/src/examples/Akka.Persistence.Custom/Snapshot/SqliteSnapshotStore.cs @@ -181,6 +181,10 @@ private bool WaitingForInitialization(object message) } // + [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) + => LoadAsync(persistenceId, criteria, CancellationToken.None); + // protected sealed override async Task LoadAsync( string persistenceId, @@ -232,6 +236,10 @@ protected sealed override async Task LoadAsync( } // + [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) + => SaveAsync(metadata, snapshot, CancellationToken.None); + // protected sealed override async Task SaveAsync( SnapshotMetadata metadata, @@ -303,6 +311,10 @@ protected sealed override async Task SaveAsync( } // + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteAsync(SnapshotMetadata metadata) + => DeleteAsync(metadata, CancellationToken.None); + // protected sealed override async Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { @@ -345,6 +357,10 @@ protected sealed override async Task DeleteAsync(SnapshotMetadata metadata, Canc } // + [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) + => DeleteAsync(persistenceId, criteria, CancellationToken.None); + // protected sealed override async Task DeleteAsync( string persistenceId, From 704731a240e453c45c561e37ae4a6820b9be2b67 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Thu, 8 May 2025 03:45:20 +0700 Subject: [PATCH 05/11] cleanup obsolete warnings --- src/core/Akka.Persistence/Journal/MemoryJournal.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core/Akka.Persistence/Journal/MemoryJournal.cs b/src/core/Akka.Persistence/Journal/MemoryJournal.cs index a6f516139d6..7f653db220e 100644 --- a/src/core/Akka.Persistence/Journal/MemoryJournal.cs +++ b/src/core/Akka.Persistence/Journal/MemoryJournal.cs @@ -32,6 +32,7 @@ public class MemoryJournal : AsyncWriteJournal protected virtual ConcurrentDictionary> Messages { get { return _messages; } } + [Obsolete("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1.5.42")] protected override Task> WriteMessagesAsync(IEnumerable messages) => WriteMessagesAsync(messages, CancellationToken.None); @@ -63,6 +64,7 @@ protected override Task> WriteMessagesAsync(IEnumerabl return Task.FromResult>(null); // all good } + [Obsolete("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead. Since 1.5.42")] public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) => ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr, CancellationToken.None); @@ -80,6 +82,7 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten return Task.CompletedTask; } + [Obsolete("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Since 1.5.42")] protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) => DeleteMessagesToAsync(persistenceId, toSequenceNr, CancellationToken.None); From fa4485a0306e58c1c6e179a3f28a5534b8aaad95 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Thu, 8 May 2025 19:48:43 +0700 Subject: [PATCH 06/11] Update API Approval list --- ...oreAPISpec.ApproveCore.DotNet.verified.txt | 12 +++-- .../CoreAPISpec.ApproveCore.Net.verified.txt | 12 +++-- ...pec.ApprovePersistence.DotNet.verified.txt | 53 +++++++++++++++++++ ...PISpec.ApprovePersistence.Net.verified.txt | 53 +++++++++++++++++++ 4 files changed, 122 insertions(+), 8 deletions(-) diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt index d987ee03b28..4491e92071c 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.DotNet.verified.txt @@ -4529,16 +4529,20 @@ namespace Akka.Pattern public Akka.Pattern.CircuitBreaker OnHalfOpen(System.Action callback) { } public Akka.Pattern.CircuitBreaker OnOpen(System.Action callback) { } public void Succeed() { } - [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter." + + " Since 1.5.42")] public System.Threading.Tasks.Task WithCircuitBreaker(System.Func> body) { } public System.Threading.Tasks.Task WithCircuitBreaker(System.Func> body) { } - [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter." + + " Since 1.5.42")] public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func> body) { } public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func> body) { } - [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter." + + " Since 1.5.42")] public System.Threading.Tasks.Task WithCircuitBreaker(System.Func body) { } public System.Threading.Tasks.Task WithCircuitBreaker(System.Func body) { } - [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter." + + " Since 1.5.42")] public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func body) { } public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func body) { } public Akka.Pattern.CircuitBreaker WithExponentialBackoff(System.TimeSpan maxResetTimeout) { } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt index 2f9dcf246d9..dca0ee41e74 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApproveCore.Net.verified.txt @@ -4519,16 +4519,20 @@ namespace Akka.Pattern public Akka.Pattern.CircuitBreaker OnHalfOpen(System.Action callback) { } public Akka.Pattern.CircuitBreaker OnOpen(System.Action callback) { } public void Succeed() { } - [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter." + + " Since 1.5.42")] public System.Threading.Tasks.Task WithCircuitBreaker(System.Func> body) { } public System.Threading.Tasks.Task WithCircuitBreaker(System.Func> body) { } - [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter." + + " Since 1.5.42")] public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func> body) { } public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func> body) { } - [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter." + + " Since 1.5.42")] public System.Threading.Tasks.Task WithCircuitBreaker(System.Func body) { } public System.Threading.Tasks.Task WithCircuitBreaker(System.Func body) { } - [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter")] + [System.ObsoleteAttribute("Use WithCircuitBreaker() that accepts functions with CancellationToken parameter." + + " Since 1.5.42")] public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func body) { } public System.Threading.Tasks.Task WithCircuitBreaker(TState state, System.Func body) { } public Akka.Pattern.CircuitBreaker WithExponentialBackoff(System.TimeSpan maxResetTimeout) { } diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.DotNet.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.DotNet.verified.txt index d56d0a2edd9..7261fde8c63 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.DotNet.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.DotNet.verified.txt @@ -857,13 +857,22 @@ namespace Akka.Persistence.Journal { protected readonly bool CanPublish; protected AsyncWriteJournal() { } + [System.ObsoleteAttribute("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Sinc" + + "e 1.5.42")] + protected abstract System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr); protected abstract System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken); + [System.ObsoleteAttribute("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead." + + " Since 1.5.42")] + public abstract System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); public abstract System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken); protected virtual bool Receive(object message) { } protected virtual bool ReceivePluginInternal(object message) { } protected bool ReceiveWriteJournal(object message) { } public abstract System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback); protected static System.Exception TryUnwrapException(System.Exception e) { } + [System.ObsoleteAttribute("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1" + + ".5.42")] + protected abstract System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages); protected abstract System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken); } public abstract class AsyncWriteProxy : Akka.Persistence.Journal.AsyncWriteJournal, Akka.Actor.IActorStash, Akka.Actor.IWithUnboundedStash, Akka.Actor.IWithUnrestrictedStash, Akka.Dispatch.IRequiresMessageQueue @@ -957,6 +966,9 @@ namespace Akka.Persistence.Journal } public interface IAsyncRecovery { + [System.ObsoleteAttribute("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead." + + " Since 1.5.42")] + System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken); System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback); } @@ -988,13 +1000,22 @@ namespace Akka.Persistence.Journal protected virtual System.Collections.Concurrent.ConcurrentDictionary> Messages { get; } public System.Collections.Generic.IDictionary> Add(Akka.Persistence.IPersistentRepresentation persistent) { } public System.Collections.Generic.IDictionary> Delete(string pid, long seqNr) { } + [System.ObsoleteAttribute("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Sinc" + + "e 1.5.42")] + protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) { } protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken) { } public long HighestSequenceNr(string pid) { } public System.Collections.Generic.IEnumerable Read(string pid, long fromSeqNr, long toSeqNr, long max) { } + [System.ObsoleteAttribute("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead." + + " Since 1.5.42")] + public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) { } public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken) { } protected override bool ReceivePluginInternal(object message) { } public override System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback) { } public System.Collections.Generic.IDictionary> Update(string pid, long seqNr, System.Func updater) { } + [System.ObsoleteAttribute("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1" + + ".5.42")] + protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages) { } protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken) { } public sealed class CurrentPersistenceIds : Akka.Event.IDeadLetterSuppression { @@ -1166,13 +1187,21 @@ namespace Akka.Persistence.Snapshot public class LocalSnapshotStore : Akka.Persistence.Snapshot.SnapshotStore { public LocalSnapshotStore() { } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } protected System.IO.FileInfo GetSnapshotFileForWrite(Akka.Persistence.SnapshotMetadata metadata, string extension = "") { } + [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } protected override void PreStart() { } protected override bool ReceivePluginInternal(object message) { } protected virtual void Save(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } + [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } protected void Serialize(System.IO.Stream stream, Akka.Persistence.Serialization.Snapshot snapshot) { } protected System.IO.FileInfo WithOutputStream(Akka.Persistence.SnapshotMetadata metadata, System.Action p) { } @@ -1181,17 +1210,33 @@ namespace Akka.Persistence.Snapshot { public MemorySnapshotStore() { } protected virtual System.Collections.Generic.List Snapshots { get; } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } } public sealed class NoSnapshotStore : Akka.Persistence.Snapshot.SnapshotStore { public NoSnapshotStore() { } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } public class NoSnapshotStoreException : System.Exception { @@ -1213,11 +1258,19 @@ namespace Akka.Persistence.Snapshot public abstract class SnapshotStore : Akka.Actor.ActorBase { protected SnapshotStore() { } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata); protected abstract System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken); + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria); protected abstract System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken); + [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria); protected abstract System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken); protected virtual bool Receive(object message) { } protected virtual bool ReceivePluginInternal(object message) { } + [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot); protected abstract System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.Net.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.Net.verified.txt index a136e19d3d9..6741f90b061 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.Net.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.Net.verified.txt @@ -857,13 +857,22 @@ namespace Akka.Persistence.Journal { protected readonly bool CanPublish; protected AsyncWriteJournal() { } + [System.ObsoleteAttribute("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Sinc" + + "e 1.5.42")] + protected abstract System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr); protected abstract System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken); + [System.ObsoleteAttribute("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead." + + " Since 1.5.42")] + public abstract System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); public abstract System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken); protected virtual bool Receive(object message) { } protected virtual bool ReceivePluginInternal(object message) { } protected bool ReceiveWriteJournal(object message) { } public abstract System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback); protected static System.Exception TryUnwrapException(System.Exception e) { } + [System.ObsoleteAttribute("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1" + + ".5.42")] + protected abstract System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages); protected abstract System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken); } public abstract class AsyncWriteProxy : Akka.Persistence.Journal.AsyncWriteJournal, Akka.Actor.IActorStash, Akka.Actor.IWithUnboundedStash, Akka.Actor.IWithUnrestrictedStash, Akka.Dispatch.IRequiresMessageQueue @@ -957,6 +966,9 @@ namespace Akka.Persistence.Journal } public interface IAsyncRecovery { + [System.ObsoleteAttribute("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead." + + " Since 1.5.42")] + System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken); System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback); } @@ -988,13 +1000,22 @@ namespace Akka.Persistence.Journal protected virtual System.Collections.Concurrent.ConcurrentDictionary> Messages { get; } public System.Collections.Generic.IDictionary> Add(Akka.Persistence.IPersistentRepresentation persistent) { } public System.Collections.Generic.IDictionary> Delete(string pid, long seqNr) { } + [System.ObsoleteAttribute("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Sinc" + + "e 1.5.42")] + protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) { } protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken) { } public long HighestSequenceNr(string pid) { } public System.Collections.Generic.IEnumerable Read(string pid, long fromSeqNr, long toSeqNr, long max) { } + [System.ObsoleteAttribute("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead." + + " Since 1.5.42")] + public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) { } public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken) { } protected override bool ReceivePluginInternal(object message) { } public override System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback) { } public System.Collections.Generic.IDictionary> Update(string pid, long seqNr, System.Func updater) { } + [System.ObsoleteAttribute("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1" + + ".5.42")] + protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages) { } protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken) { } public sealed class CurrentPersistenceIds : Akka.Event.IDeadLetterSuppression { @@ -1164,13 +1185,21 @@ namespace Akka.Persistence.Snapshot public class LocalSnapshotStore : Akka.Persistence.Snapshot.SnapshotStore { public LocalSnapshotStore() { } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } protected System.IO.FileInfo GetSnapshotFileForWrite(Akka.Persistence.SnapshotMetadata metadata, string extension = "") { } + [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } protected override void PreStart() { } protected override bool ReceivePluginInternal(object message) { } protected virtual void Save(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } + [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } protected void Serialize(System.IO.Stream stream, Akka.Persistence.Serialization.Snapshot snapshot) { } protected System.IO.FileInfo WithOutputStream(Akka.Persistence.SnapshotMetadata metadata, System.Action p) { } @@ -1179,17 +1208,33 @@ namespace Akka.Persistence.Snapshot { public MemorySnapshotStore() { } protected virtual System.Collections.Generic.List Snapshots { get; } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } } public sealed class NoSnapshotStore : Akka.Persistence.Snapshot.SnapshotStore { public NoSnapshotStore() { } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } + [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } public class NoSnapshotStoreException : System.Exception { @@ -1211,11 +1256,19 @@ namespace Akka.Persistence.Snapshot public abstract class SnapshotStore : Akka.Actor.ActorBase { protected SnapshotStore() { } + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata); protected abstract System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken); + [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria); protected abstract System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken); + [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria); protected abstract System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken); protected virtual bool Receive(object message) { } protected virtual bool ReceivePluginInternal(object message) { } + [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] + protected abstract System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot); protected abstract System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken); } } \ No newline at end of file From ec198763b7f3566488c49b44947e307b4fd14afe Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Thu, 8 May 2025 21:09:48 +0700 Subject: [PATCH 07/11] Cleanup refactor warnings --- src/core/Akka.Persistence/Journal/AsyncRecovery.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Akka.Persistence/Journal/AsyncRecovery.cs b/src/core/Akka.Persistence/Journal/AsyncRecovery.cs index 86bc81ad665..53877e4d1ad 100644 --- a/src/core/Akka.Persistence/Journal/AsyncRecovery.cs +++ b/src/core/Akka.Persistence/Journal/AsyncRecovery.cs @@ -25,7 +25,7 @@ public interface IAsyncRecovery /// could not be replayed. /// /// The is the lowest of what was returned by - /// and what the user specified as recovery + /// and what the user specified as recovery /// parameter. /// This does imply that this call is always preceded by reading the highest sequence number /// for the given . From f0dfad8f50b0407abcb4c23dcd7c217622c4dceb Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Fri, 9 May 2025 22:45:12 +0700 Subject: [PATCH 08/11] Revert `.ContinueWith()` refactor --- .../SnapshotStoreProxy.cs | 16 +-- .../Journal/AsyncWriteJournal.cs | 78 +++++------- .../Journal/AsyncWriteProxy.cs | 28 ++-- .../Snapshot/MemorySnapshotStore.cs | 8 +- .../Snapshot/SnapshotStore.cs | 120 ++++++------------ src/core/Akka/Util/Internal/AtomicState.cs | 16 --- 6 files changed, 93 insertions(+), 173 deletions(-) diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs index 60484ac3b50..d35e5e6065b 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs @@ -102,9 +102,7 @@ protected override async Task DeleteAsync( throw new TimeoutException("Store not initialized."); try { - using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - cts.CancelAfter(Timeout); - var response = await _store.Ask(new DeleteSnapshot(metadata), cts.Token); + var response = await _store.Ask(new DeleteSnapshot(metadata), Timeout, cancellationToken); if (response is DeleteSnapshotFailure f) { ExceptionDispatchInfo.Capture(f.Cause).Throw(); @@ -129,9 +127,7 @@ protected override async Task DeleteAsync( throw new TimeoutException("Store not initialized."); try { - using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - cts.CancelAfter(Timeout); - var response = await _store.Ask(new DeleteSnapshots(persistenceId, criteria), cts.Token); + var response = await _store.Ask(new DeleteSnapshots(persistenceId, criteria), Timeout, cancellationToken); if (response is DeleteSnapshotsFailure f) { ExceptionDispatchInfo.Capture(f.Cause).Throw(); @@ -156,9 +152,7 @@ protected override async Task LoadAsync( throw new TimeoutException("Store not initialized."); try { - using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - cts.CancelAfter(Timeout); - var response = await _store.Ask(new LoadSnapshot(persistenceId, criteria, criteria.MaxSequenceNr), cts.Token); + var response = await _store.Ask(new LoadSnapshot(persistenceId, criteria, criteria.MaxSequenceNr), Timeout, cancellationToken); switch (response) { case LoadSnapshotResult ls: @@ -191,9 +185,7 @@ protected override async Task SaveAsync( throw new TimeoutException("Store not initialized."); try { - using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - cts.CancelAfter(Timeout); - var response = await _store.Ask(new SaveSnapshot(metadata, snapshot), cts.Token); + var response = await _store.Ask(new SaveSnapshot(metadata, snapshot), Timeout, cancellationToken); if (response is SaveSnapshotFailure f) { ExceptionDispatchInfo.Capture(f.Cause).Throw(); diff --git a/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs b/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs index 31a36448451..c138e80aebd 100644 --- a/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs +++ b/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs @@ -343,6 +343,16 @@ private void HandleReplayMessages(ReplayMessages message) async Task ExecuteHighestSequenceNr() { + void CompleteHighSeqNo(long highSeqNo) + { + replyTo.Tell(new RecoverySuccess(highSeqNo)); + + if (CanPublish) + { + eventStream.Publish(message); + } + } + try { var highSequenceNr = await _breaker.WithCircuitBreaker( @@ -350,7 +360,11 @@ async Task ExecuteHighestSequenceNr() (state, ct) => state.awj.ReadHighestSequenceNrAsync(state.message.PersistenceId, state.readHighestSequenceNrFrom, ct)); var toSequenceNr = Math.Min(message.ToSequenceNr, highSequenceNr); - if (toSequenceNr > 0L && message.FromSequenceNr <= toSequenceNr) + if (toSequenceNr <= 0L || message.FromSequenceNr > toSequenceNr) + { + CompleteHighSeqNo(highSequenceNr); + } + else { // Send replayed messages and replay result to persistentActor directly. No need // to resequence replayed messages relative to written and looped messages. @@ -368,12 +382,7 @@ await ReplayMessagesAsync(context, message.PersistenceId, message.FromSequenceNr }); } - replyTo.Tell(new RecoverySuccess(highSequenceNr)); - - if (CanPublish) - { - eventStream.Publish(message); - } + CompleteHighSeqNo(highSequenceNr); } catch (OperationCanceledException cx) { @@ -434,9 +443,7 @@ private async Task ExecuteBatch(WriteMessages message, int atomicWriteCount, IAc try { var writeResult = - await _breaker.WithCircuitBreaker( - state: (prepared, awj: this), - body: (state, ct) => state.awj.WriteMessagesAsync(state.prepared, ct)).ConfigureAwait(false); + await _breaker.WithCircuitBreaker((prepared, awj: this), (state, ct) => state.awj.WriteMessagesAsync(state.prepared, ct)).ConfigureAwait(false); ProcessResults(writeResult, atomicWriteCount, message, _resequencer, resequencerCounter, self); } @@ -467,51 +474,34 @@ private void ProcessResults(IImmutableList results, int atomicWriteCo : new WriteMessageRejected(x, exception, writeMessage.ActorInstanceId), results, resequencerCounter, writeMessage, resequencer, writeJournal); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void Resequence( - Func mapper, - IImmutableList results, - long resequencerCounter, - WriteMessages msg, - IActorRef resequencer, - IActorRef writeJournal) + private static void Resequence(Func mapper, + IImmutableList results, long resequencerCounter, WriteMessages msg, IActorRef resequencer, IActorRef writeJournal) { var i = 0; var enumerator = results?.GetEnumerator(); - try + foreach (var resequencable in msg.Messages) { - foreach (var resequencable in msg.Messages) + if (resequencable is AtomicWrite aw) { - if (resequencable is AtomicWrite aw) + Exception exception = null; + if (enumerator != null) { - Exception exception = null; - if (enumerator != null) - { - enumerator.MoveNext(); - exception = enumerator.Current; - } - - foreach (var p in (IEnumerable)aw.Payload) - { - resequencer.Tell( - new Desequenced(mapper(p, exception), resequencerCounter + i + 1, msg.PersistentActor, - p.Sender), writeJournal); - i++; - } + enumerator.MoveNext(); + exception = enumerator.Current; } - else + + foreach (var p in (IEnumerable)aw.Payload) { - var loopMsg = new LoopMessageSuccess(resequencable.Payload, msg.ActorInstanceId); - resequencer.Tell( - new Desequenced(loopMsg, resequencerCounter + i + 1, msg.PersistentActor, - resequencable.Sender), writeJournal); + resequencer.Tell(new Desequenced(mapper(p, exception), resequencerCounter + i + 1, msg.PersistentActor, p.Sender), writeJournal); i++; } } - } - finally - { - enumerator?.Dispose(); + else + { + var loopMsg = new LoopMessageSuccess(resequencable.Payload, msg.ActorInstanceId); + resequencer.Tell(new Desequenced(loopMsg, resequencerCounter + i + 1, msg.PersistentActor, resequencable.Sender), writeJournal); + i++; + } } } diff --git a/src/core/Akka.Persistence/Journal/AsyncWriteProxy.cs b/src/core/Akka.Persistence/Journal/AsyncWriteProxy.cs index 1f3c8662642..e4eedc8735e 100644 --- a/src/core/Akka.Persistence/Journal/AsyncWriteProxy.cs +++ b/src/core/Akka.Persistence/Journal/AsyncWriteProxy.cs @@ -9,6 +9,7 @@ using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Runtime.CompilerServices; using System.Threading.Tasks; using Akka.Actor; using System.Runtime.Serialization; @@ -330,16 +331,14 @@ protected internal override bool AroundReceive(Receive receive, object message) /// This exception is thrown when the store has not been initialized. /// /// TBD - protected override async Task> WriteMessagesAsync( + protected override Task> WriteMessagesAsync( IEnumerable messages, CancellationToken cancellationToken) { if (_store == null) - throw new TimeoutException("Store not initialized."); + return StoreNotInitialized>(); - using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - cts.CancelAfter(Timeout); - return await _store.Ask>(new AsyncWriteTarget.WriteMessages(messages), cts.Token); + return _store.Ask>(new AsyncWriteTarget.WriteMessages(messages), Timeout, cancellationToken); } /// @@ -352,17 +351,15 @@ protected override async Task> WriteMessagesAsync( /// This exception is thrown when the store has not been initialized. /// /// TBD - protected override async Task DeleteMessagesToAsync( + protected override Task DeleteMessagesToAsync( string persistenceId, long toSequenceNr, CancellationToken cancellationToken) { if (_store == null) - throw new TimeoutException("Store not initialized."); + return StoreNotInitialized(); - using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - cts.CancelAfter(Timeout); - await _store.Ask(new AsyncWriteTarget.DeleteMessagesTo(persistenceId, toSequenceNr), cts.Token); + return _store.Ask(new AsyncWriteTarget.DeleteMessagesTo(persistenceId, toSequenceNr), Timeout, cancellationToken); } /// @@ -401,20 +398,19 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten /// This exception is thrown when the store has not been initialized. /// /// TBD - public override async Task ReadHighestSequenceNrAsync( + public override Task ReadHighestSequenceNrAsync( string persistenceId, long fromSequenceNr, CancellationToken cancellationToken) { if (_store == null) - throw new TimeoutException("Store not initialized."); + return StoreNotInitialized(); - using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); - cts.CancelAfter(Timeout); - return (await _store.Ask(new AsyncWriteTarget.ReplayMessages(persistenceId, 0, 0, 0), cts.Token)).HighestSequenceNr; + return _store.Ask(new AsyncWriteTarget.ReplayMessages(persistenceId, 0, 0, 0), Timeout, cancellationToken) + .ContinueWith(t => t.Result.HighestSequenceNr, TaskContinuationOptions.OnlyOnRanToCompletion); } - private Task StoreNotInitialized() + private static Task StoreNotInitialized() { var promise = new TaskCompletionSource(); promise.SetException(new TimeoutException("Store not initialized.")); diff --git a/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs index f53cebabb77..a3b10200583 100644 --- a/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs @@ -33,15 +33,13 @@ protected override Task DeleteAsync(SnapshotMetadata metadata) protected override Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { + bool Pred(SnapshotEntry x) => x.PersistenceId == metadata.PersistenceId && (metadata.SequenceNr <= 0 || metadata.SequenceNr == long.MaxValue || x.SequenceNr == metadata.SequenceNr) + && (metadata.Timestamp == DateTime.MinValue || metadata.Timestamp == DateTime.MaxValue || x.Timestamp == metadata.Timestamp.Ticks); + var snapshot = Snapshots.FirstOrDefault(Pred); Snapshots.Remove(snapshot); return TaskEx.Completed; - - bool Pred(SnapshotEntry x) => - x.PersistenceId == metadata.PersistenceId - && (metadata.SequenceNr <= 0 || metadata.SequenceNr == long.MaxValue || x.SequenceNr == metadata.SequenceNr) - && (metadata.Timestamp == DateTime.MinValue || metadata.Timestamp == DateTime.MaxValue || x.Timestamp == metadata.Timestamp.Ticks); } [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] diff --git a/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs index 5955c4afde2..ed4aa5e7cb3 100644 --- a/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs @@ -68,26 +68,15 @@ private bool ReceiveSnapshotStore(object message) break; case LoadSnapshot loadSnapshot: - _breaker.WithCircuitBreaker(InvokeLoadAsync) + _breaker.WithCircuitBreaker(ct => LoadAsync(loadSnapshot.PersistenceId, loadSnapshot.Criteria.Limit(loadSnapshot.ToSequenceNr), ct)) + .ContinueWith(t => (!t.IsFaulted && !t.IsCanceled) + ? new LoadSnapshotResult(t.Result, loadSnapshot.ToSequenceNr) as ISnapshotResponse + : new LoadSnapshotFailed(t.IsFaulted + ? TryUnwrapException(t.Exception) + : new OperationCanceledException("LoadAsync canceled, possibly due to timing out.")), + _continuationOptions) .PipeTo(senderPersistentActor); break; - - async Task InvokeLoadAsync(CancellationToken cancellationToken) - { - try - { - return new LoadSnapshotResult( - snapshot: await LoadAsync( - persistenceId: loadSnapshot.PersistenceId, - criteria: loadSnapshot.Criteria.Limit(loadSnapshot.ToSequenceNr), - cancellationToken: cancellationToken), - toSequenceNr: loadSnapshot.ToSequenceNr); - } - catch (Exception e) - { - return new LoadSnapshotFailed(TryUnwrapException(e)); - } - } case SaveSnapshot saveSnapshot: var metadata = new SnapshotMetadata( @@ -96,24 +85,16 @@ async Task InvokeLoadAsync(CancellationToken cancellationToke timestamp: saveSnapshot.Metadata.Timestamp == DateTime.MinValue ? DateTime.UtcNow : saveSnapshot.Metadata.Timestamp); - - _breaker.WithCircuitBreaker(InvokeSaveAsync) + _breaker.WithCircuitBreaker(ct => SaveAsync(metadata, saveSnapshot.Snapshot, ct)) + .ContinueWith(t => (!t.IsFaulted && !t.IsCanceled) + ? new SaveSnapshotSuccess(metadata) as ISnapshotResponse + : new SaveSnapshotFailure(saveSnapshot.Metadata, + t.IsFaulted + ? TryUnwrapException(t.Exception) + : new OperationCanceledException("SaveAsync canceled, possibly due to timing out.", TryUnwrapException(t.Exception))), + _continuationOptions) .PipeTo(self, senderPersistentActor); - break; - - async Task InvokeSaveAsync(CancellationToken cancellationToken) - { - try - { - await SaveAsync(metadata, saveSnapshot.Snapshot, cancellationToken); - return new SaveSnapshotSuccess(metadata); - } - catch (Exception e) - { - return new SaveSnapshotFailure(saveSnapshot.Metadata, TryUnwrapException(e)); - } - } case SaveSnapshotSuccess: try @@ -124,59 +105,47 @@ async Task InvokeSaveAsync(CancellationToken cancellationToke { senderPersistentActor.Tell(message); } - break; case SaveSnapshotFailure saveSnapshotFailure: try { ReceivePluginInternal(message); - _breaker.WithCircuitBreaker(InvokeDeleteAsync); - - async Task InvokeDeleteAsync(CancellationToken cancellationToken) - { - try - { - await DeleteAsync(saveSnapshotFailure.Metadata, cancellationToken); - } - catch (Exception e) + _breaker.WithCircuitBreaker(ct => DeleteAsync(saveSnapshotFailure.Metadata, ct)) + .ContinueWith(t => { - _log.Error(TryUnwrapException(e), "DeleteAsync operation after SaveSnapshot failure failed."); - } - } + if(t.IsFaulted) + _log.Error(t.Exception, "DeleteAsync operation after SaveSnapshot failure failed."); + else if(t.IsCanceled) + _log.Error(t.Exception, t.Exception is not null + ? "DeleteAsync operation after SaveSnapshot failure canceled." + : "DeleteAsync operation after SaveSnapshot failure canceled, possibly due to timing out."); + }, TaskContinuationOptions.ExecuteSynchronously); } finally { senderPersistentActor.Tell(message); } - break; case DeleteSnapshot deleteSnapshot: { var eventStream = Context.System.EventStream; - _breaker.WithCircuitBreaker(InvokeDeleteAsync) + _breaker.WithCircuitBreaker(ct => DeleteAsync(deleteSnapshot.Metadata, ct)) + .ContinueWith(t => (!t.IsFaulted && !t.IsCanceled) + ? new DeleteSnapshotSuccess(deleteSnapshot.Metadata) as ISnapshotResponse + : new DeleteSnapshotFailure(deleteSnapshot.Metadata, + t.IsFaulted + ? TryUnwrapException(t.Exception) + : new OperationCanceledException("DeleteAsync canceled, possibly due to timing out.")), + _continuationOptions) .PipeTo(self, senderPersistentActor) .ContinueWith(_ => { if (_publish) eventStream.Publish(message); }, _continuationOptions); - break; - - async Task InvokeDeleteAsync(CancellationToken cancellationToken) - { - try - { - await DeleteAsync(deleteSnapshot.Metadata, cancellationToken); - return new DeleteSnapshotSuccess(deleteSnapshot.Metadata); - } - catch (Exception e) - { - return new DeleteSnapshotFailure(deleteSnapshot.Metadata, TryUnwrapException(e)); - } - } } case DeleteSnapshotSuccess: @@ -188,7 +157,6 @@ async Task InvokeDeleteAsync(CancellationToken cancellationTo { senderPersistentActor.Tell(message); } - break; case DeleteSnapshotFailure: @@ -200,13 +168,19 @@ async Task InvokeDeleteAsync(CancellationToken cancellationTo { senderPersistentActor.Tell(message); } - break; case DeleteSnapshots deleteSnapshots: { var eventStream = Context.System.EventStream; - _breaker.WithCircuitBreaker(InvokeDeleteAsync) + _breaker.WithCircuitBreaker(ct => DeleteAsync(deleteSnapshots.PersistenceId, deleteSnapshots.Criteria, ct)) + .ContinueWith(t => (!t.IsFaulted && !t.IsCanceled) + ? new DeleteSnapshotsSuccess(deleteSnapshots.Criteria) as ISnapshotResponse + : new DeleteSnapshotsFailure(deleteSnapshots.Criteria, + t.IsFaulted + ? TryUnwrapException(t.Exception) + : new OperationCanceledException("DeleteAsync canceled, possibly due to timing out.")), + _continuationOptions) .PipeTo(self, senderPersistentActor) .ContinueWith(_ => { @@ -214,19 +188,6 @@ async Task InvokeDeleteAsync(CancellationToken cancellationTo eventStream.Publish(message); }, _continuationOptions); break; - - async Task InvokeDeleteAsync(CancellationToken cancellationToken) - { - try - { - await DeleteAsync(deleteSnapshots.PersistenceId, deleteSnapshots.Criteria, cancellationToken); - return new DeleteSnapshotsSuccess(deleteSnapshots.Criteria); - } - catch (Exception e) - { - return new DeleteSnapshotsFailure(deleteSnapshots.Criteria, TryUnwrapException(e)); - } - } } case DeleteSnapshotsSuccess: @@ -238,7 +199,6 @@ async Task InvokeDeleteAsync(CancellationToken cancellationTo { senderPersistentActor.Tell(message); } - break; case DeleteSnapshotsFailure: diff --git a/src/core/Akka/Util/Internal/AtomicState.cs b/src/core/Akka/Util/Internal/AtomicState.cs index 978ec84e2d9..1e332c62b37 100644 --- a/src/core/Akka/Util/Internal/AtomicState.cs +++ b/src/core/Akka/Util/Internal/AtomicState.cs @@ -87,8 +87,6 @@ public async Task CallThrough(Func> task) } catch (Exception ex) { - if (ex is TaskCanceledException) - ex = new TimeoutException("Task was cancelled, probably because of a timeout", ex); var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); @@ -114,8 +112,6 @@ public async Task CallThrough(Func> task) } catch (Exception ex) { - if (ex is TaskCanceledException) - ex = new TimeoutException("Task was cancelled, probably because of a timeout", ex); var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); @@ -134,8 +130,6 @@ public async Task CallThrough(TState state, Func> } catch (Exception ex) { - if (ex is TaskCanceledException) - ex = new TimeoutException("Task was cancelled, probably because of a timeout", ex); var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); @@ -155,8 +149,6 @@ public async Task CallThrough(TState state, Func task) } catch (Exception ex) { - if (ex is TaskCanceledException) - ex = new TimeoutException("Task was cancelled, probably because of a timeout", ex); var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); @@ -204,8 +194,6 @@ public async Task CallThrough(Func task) } catch (Exception ex) { - if (ex is TaskCanceledException) - ex = new TimeoutException("Task was cancelled, probably because of a timeout", ex); var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); @@ -221,8 +209,6 @@ public async Task CallThrough(TState state, Func task) } catch (Exception ex) { - if (ex is TaskCanceledException) - ex = new TimeoutException("Task was cancelled, probably because of a timeout", ex); var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); @@ -239,8 +225,6 @@ public async Task CallThrough(TState state, Func Date: Fri, 9 May 2025 23:08:01 +0700 Subject: [PATCH 09/11] Code cleanup, remove stupid codes --- .../AsyncWriteProxyEx.cs | 31 ++---- .../SnapshotStoreProxy.cs | 16 --- .../Bugfix7399Specs.cs | 16 --- .../Journal/ChaosJournal.cs | 12 --- .../Akka.Persistence/Journal/AsyncRecovery.cs | 22 ---- .../Journal/AsyncWriteJournal.cs | 101 ++---------------- .../Akka.Persistence/Journal/MemoryJournal.cs | 12 --- .../Snapshot/LocalSnapshotStore.cs | 16 --- .../Snapshot/MemorySnapshotStore.cs | 16 --- .../Snapshot/NoSnapshotStore.cs | 24 ----- .../Snapshot/SnapshotStore.cs | 45 -------- .../Journal/SqliteJournal.cs | 12 --- .../Snapshot/SqliteSnapshotStore.cs | 16 --- 13 files changed, 15 insertions(+), 324 deletions(-) diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/AsyncWriteProxyEx.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/AsyncWriteProxyEx.cs index 6d9def40ca2..c6a285b5bd3 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/AsyncWriteProxyEx.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/AsyncWriteProxyEx.cs @@ -156,10 +156,6 @@ protected internal override bool AroundReceive(Receive receive, object message) return true; } - [Obsolete("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task> WriteMessagesAsync(IEnumerable messages) - => WriteMessagesAsync(messages, CancellationToken.None); - protected override Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { var trueMsgs = messages.ToArray(); @@ -184,10 +180,6 @@ protected override Task> WriteMessagesAsync(IEnumerabl }, TaskContinuationOptions.ExecuteSynchronously); } - [Obsolete("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) - => DeleteMessagesToAsync(persistenceId, toSequenceNr, CancellationToken.None); - protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, CancellationToken cancellationToken) { if (_store == null) @@ -195,16 +187,15 @@ protected override Task DeleteMessagesToAsync(string persistenceId, long toSeque var result = new TaskCompletionSource(); - _store.Ask(sender => new DeleteMessagesTo(persistenceId, toSequenceNr, sender), Timeout, cancellationToken) - .ContinueWith(r => - { - if (r.IsFaulted) - result.TrySetException(r.Exception); - else if (r.IsCanceled) - result.TrySetException(new TimeoutException()); - else - result.TrySetResult(true); - }, TaskContinuationOptions.ExecuteSynchronously); + _store.Ask(sender => new DeleteMessagesTo(persistenceId, toSequenceNr, sender), Timeout, cancellationToken).ContinueWith(r => + { + if (r.IsFaulted) + result.TrySetException(r.Exception); + else if (r.IsCanceled) + result.TrySetException(new TimeoutException()); + else + result.TrySetResult(true); + }, TaskContinuationOptions.ExecuteSynchronously); return result.Task; } @@ -235,10 +226,6 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten return replayCompletionPromise.Task; } - [Obsolete("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) - => ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr, CancellationToken.None); - public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken) { if (_store == null) diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs index d35e5e6065b..0973d5fc755 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests.MultiNode/SnapshotStoreProxy.cs @@ -90,10 +90,6 @@ protected internal override bool AroundReceive(Receive receive, object message) return true; } - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteAsync(SnapshotMetadata metadata) - => DeleteAsync(metadata, CancellationToken.None); - protected override async Task DeleteAsync( SnapshotMetadata metadata, CancellationToken cancellationToken) @@ -114,10 +110,6 @@ protected override async Task DeleteAsync( } } - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) - => DeleteAsync(persistenceId, criteria, CancellationToken.None); - protected override async Task DeleteAsync( string persistenceId, SnapshotSelectionCriteria criteria, @@ -139,10 +131,6 @@ protected override async Task DeleteAsync( } } - [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) - => LoadAsync(persistenceId, criteria, CancellationToken.None); - protected override async Task LoadAsync( string persistenceId, SnapshotSelectionCriteria criteria, @@ -172,10 +160,6 @@ protected override async Task LoadAsync( throw new TimeoutException(); } - [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) - => SaveAsync(metadata, snapshot, CancellationToken.None); - protected override async Task SaveAsync( SnapshotMetadata metadata, object snapshot, diff --git a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/Bugfix7399Specs.cs b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/Bugfix7399Specs.cs index 4880358f7d2..5c62adf13db 100644 --- a/src/contrib/cluster/Akka.Cluster.Sharding.Tests/Bugfix7399Specs.cs +++ b/src/contrib/cluster/Akka.Cluster.Sharding.Tests/Bugfix7399Specs.cs @@ -166,10 +166,6 @@ public class FailingSnapshot : SnapshotStore { public static bool Working = false; - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteAsync(SnapshotMetadata metadata) - => DeleteAsync(metadata, CancellationToken.None); - protected override Task DeleteAsync( SnapshotMetadata metadata, CancellationToken cancellationToken) @@ -182,10 +178,6 @@ protected override Task DeleteAsync( return Task.CompletedTask; } - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) - => DeleteAsync(persistenceId, criteria, CancellationToken.None); - protected override Task DeleteAsync( string persistenceId, SnapshotSelectionCriteria criteria, @@ -199,10 +191,6 @@ protected override Task DeleteAsync( return Task.CompletedTask; } - [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) - => LoadAsync(persistenceId, criteria, CancellationToken.None); - protected override async Task LoadAsync( string persistenceId, SnapshotSelectionCriteria criteria, @@ -216,10 +204,6 @@ protected override async Task LoadAsync( return null; } - [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) - => SaveAsync(metadata, snapshot, CancellationToken.None); - protected override Task SaveAsync( SnapshotMetadata metadata, object snapshot, diff --git a/src/core/Akka.Persistence.Tests/Journal/ChaosJournal.cs b/src/core/Akka.Persistence.Tests/Journal/ChaosJournal.cs index c94bcd50536..c2ba8de4af4 100644 --- a/src/core/Akka.Persistence.Tests/Journal/ChaosJournal.cs +++ b/src/core/Akka.Persistence.Tests/Journal/ChaosJournal.cs @@ -84,10 +84,6 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten return promise.Task; } - [Obsolete("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) - => ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr, CancellationToken.None); - public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken) { var promise = new TaskCompletionSource(); @@ -98,10 +94,6 @@ public override Task ReadHighestSequenceNrAsync(string persistenceId, long return promise.Task; } - [Obsolete("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task> WriteMessagesAsync(IEnumerable messages) - => WriteMessagesAsync(messages, CancellationToken.None); - protected override Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { var promise = @@ -129,10 +121,6 @@ protected override Task> WriteMessagesAsync(IEnumerabl return promise.Task; } - [Obsolete("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) - => DeleteMessagesToAsync(persistenceId, toSequenceNr, CancellationToken.None); - protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, CancellationToken cancellationToken) { TaskCompletionSource promise = new TaskCompletionSource(); diff --git a/src/core/Akka.Persistence/Journal/AsyncRecovery.cs b/src/core/Akka.Persistence/Journal/AsyncRecovery.cs index 53877e4d1ad..87a1a3a81a6 100644 --- a/src/core/Akka.Persistence/Journal/AsyncRecovery.cs +++ b/src/core/Akka.Persistence/Journal/AsyncRecovery.cs @@ -45,28 +45,6 @@ public interface IAsyncRecovery /// TBD Task ReplayMessagesAsync(IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, Action recoveryCallback); - /// - /// Asynchronously reads the highest stored sequence number for provided . - /// The persistent actor will use the highest sequence number after recovery as the starting point when - /// persisting new events. - /// This sequence number is also used as `toSequenceNr` in subsequent calls to - /// unless the user has specified a lower `toSequenceNr`. - /// Journal must maintain the highest sequence number and never decrease it. - /// - /// This call is protected with a circuit-breaker. - /// - /// Please also not that requests for the highest sequence number may be made concurrently - /// to writes executing for the same , in particular it is - /// possible that a restarting actor tries to recover before its outstanding writes have completed. - /// - /// Persistent actor identifier - /// Hint where to start searching for the highest sequence number. - /// When a persistent actor is recovering this will the sequence - /// number of the used snapshot, or `0L` if no snapshot is used. - /// TBD - [Obsolete("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); - /// /// Asynchronously reads the highest stored sequence number for provided . /// The persistent actor will use the highest sequence number after recovery as the starting point when diff --git a/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs b/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs index c138e80aebd..779ccdff36e 100644 --- a/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs +++ b/src/core/Akka.Persistence/Journal/AsyncWriteJournal.cs @@ -79,8 +79,8 @@ protected AsyncWriteJournal() throw new ConfigurationException($"Invalid replay-filter.mode [{replayFilterMode}], supported values [off, repair-by-discard-old, fail, warn]"); } _isReplayFilterEnabled = _replayFilterMode != ReplayFilterMode.Disabled; - _replayFilterWindowSize = config.GetInt("replay-filter.window-size", 0); - _replayFilterMaxOldWriters = config.GetInt("replay-filter.max-old-writers", 0); + _replayFilterWindowSize = config.GetInt("replay-filter.window-size", 100); + _replayFilterMaxOldWriters = config.GetInt("replay-filter.max-old-writers", 10); _replayDebugEnabled = config.GetBoolean("replay-filter.debug", false); _resequencer = Context.ActorOf(Props.Create(() => new Resequencer()), "resequencer"); @@ -89,87 +89,9 @@ protected AsyncWriteJournal() /// public abstract Task ReplayMessagesAsync(IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, Action recoveryCallback); - /// - [Obsolete("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - public abstract Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); - /// public abstract Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken); - /// - /// Plugin API: asynchronously writes a batch of persistent messages to the - /// journal. - /// - /// The batch is only for performance reasons, i.e. all messages don't have to be written - /// atomically. Higher throughput can typically be achieved by using batch inserts of many - /// records compared to inserting records one-by-one, but this aspect depends on the - /// underlying data store and a journal implementation can implement it as efficient as - /// possible. Journals should aim to persist events in-order for a given `persistenceId` - /// as otherwise in case of a failure, the persistent state may be end up being inconsistent. - /// - /// Each message contains the single - /// that corresponds to the event that was passed to the - /// method of the - /// , or it contains several - /// that correspond to the events that were passed to the - /// - /// method of the . All of the - /// must be written to the data store atomically, i.e. all or none must - /// be stored. If the journal (data store) cannot support atomic writes of multiple - /// events it should reject such writes with a - /// describing the issue. This limitation should also be documented by the journal plugin. - /// - /// If there are failures when storing any of the messages in the batch the returned - /// must be completed with failure. The must only be completed with - /// success when all messages in the batch have been confirmed to be stored successfully, - /// i.e. they will be readable, and visible, in a subsequent replay. If there is - /// uncertainty about if the messages were stored or not the must be completed - /// with failure. - /// - /// Data store connection problems must be signaled by completing the with - /// failure. - /// - /// The journal can also signal that it rejects individual messages () by - /// the returned . It is possible but not mandatory to reduce - /// number of allocations by returning null for the happy path, - /// i.e. when no messages are rejected. Otherwise the returned list must have as many elements - /// as the input . Each result element signals if the corresponding - /// is rejected or not, with an exception describing the problem. Rejecting - /// a message means it was not stored, i.e. it must not be included in a later replay. - /// Rejecting a message is typically done before attempting to store it, e.g. because of - /// serialization error. - /// - /// Data store connection problems must not be signaled as rejections. - /// - /// It is possible but not mandatory to reduce number of allocations by returning - /// null for the happy path, i.e. when no messages are rejected. - /// - /// Calls to this method are serialized by the enclosing journal actor. If you spawn - /// work in asynchronous tasks it is alright that they complete the futures in any order, - /// but the actual writes for a specific persistenceId should be serialized to avoid - /// issues such as events of a later write are visible to consumers (query side, or replay) - /// before the events of an earlier write are visible. - /// A will not send a new request before - /// the previous one has been completed. - /// - /// Please not that the of the contained - /// objects has been nulled out (i.e. set to - /// in order to not use space in the journal for a sender reference that will likely be obsolete - /// during replay. - /// - /// Please also note that requests for the highest sequence number may be made concurrently - /// to this call executing for the same `persistenceId`, in particular it is possible that - /// a restarting actor tries to recover before its outstanding writes have completed. - /// In the latter case it is highly desirable to defer reading the highest sequence number - /// until all outstanding writes have completed, otherwise the - /// may reuse sequence numbers. - /// - /// This call is protected with a circuit-breaker. - /// - /// TBD - [Obsolete("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract Task> WriteMessagesAsync(IEnumerable messages); - /// /// Plugin API: asynchronously writes a batch of persistent messages to the /// journal. @@ -244,15 +166,6 @@ protected AsyncWriteJournal() /// used to signal cancelled snapshot operation protected abstract Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken); - /// - /// Asynchronously deletes all persistent messages up to inclusive - /// bound. - /// - /// TBD - /// TBD - [Obsolete("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr); - /// /// Asynchronously deletes all persistent messages up to inclusive /// bound. @@ -355,9 +268,7 @@ void CompleteHighSeqNo(long highSeqNo) try { - var highSequenceNr = await _breaker.WithCircuitBreaker( - (message, readHighestSequenceNrFrom, awj: this), - (state, ct) => + var highSequenceNr = await _breaker.WithCircuitBreaker((message, readHighestSequenceNrFrom, awj: this), (state, ct) => state.awj.ReadHighestSequenceNrAsync(state.message.PersistenceId, state.readHighestSequenceNrFrom, ct)); var toSequenceNr = Math.Min(message.ToSequenceNr, highSequenceNr); if (toSequenceNr <= 0L || message.FromSequenceNr > toSequenceNr) @@ -380,9 +291,9 @@ await ReplayMessagesAsync(context, message.PersistenceId, message.FromSequenceNr } } }); - } - CompleteHighSeqNo(highSequenceNr); + CompleteHighSeqNo(highSequenceNr); + } } catch (OperationCanceledException cx) { @@ -474,7 +385,7 @@ private void ProcessResults(IImmutableList results, int atomicWriteCo : new WriteMessageRejected(x, exception, writeMessage.ActorInstanceId), results, resequencerCounter, writeMessage, resequencer, writeJournal); } - private static void Resequence(Func mapper, + private void Resequence(Func mapper, IImmutableList results, long resequencerCounter, WriteMessages msg, IActorRef resequencer, IActorRef writeJournal) { var i = 0; diff --git a/src/core/Akka.Persistence/Journal/MemoryJournal.cs b/src/core/Akka.Persistence/Journal/MemoryJournal.cs index 7f653db220e..ff23c88efa6 100644 --- a/src/core/Akka.Persistence/Journal/MemoryJournal.cs +++ b/src/core/Akka.Persistence/Journal/MemoryJournal.cs @@ -32,10 +32,6 @@ public class MemoryJournal : AsyncWriteJournal protected virtual ConcurrentDictionary> Messages { get { return _messages; } } - [Obsolete("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task> WriteMessagesAsync(IEnumerable messages) - => WriteMessagesAsync(messages, CancellationToken.None); - protected override Task> WriteMessagesAsync(IEnumerable messages, CancellationToken cancellationToken) { foreach (var w in messages) @@ -64,10 +60,6 @@ protected override Task> WriteMessagesAsync(IEnumerabl return Task.FromResult>(null); // all good } - [Obsolete("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) - => ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr, CancellationToken.None); - public override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, CancellationToken cancellationToken) { return Task.FromResult(Math.Max(HighestSequenceNr(persistenceId), _meta.GetValueOrDefault(persistenceId, 0L))); @@ -82,10 +74,6 @@ public override Task ReplayMessagesAsync(IActorContext context, string persisten return Task.CompletedTask; } - [Obsolete("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) - => DeleteMessagesToAsync(persistenceId, toSequenceNr, CancellationToken.None); - protected override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, CancellationToken cancellationToken) { var highestSeqNr = HighestSequenceNr(persistenceId); diff --git a/src/core/Akka.Persistence/Snapshot/LocalSnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/LocalSnapshotStore.cs index 6044c7b29ca..9c1d8196c2c 100644 --- a/src/core/Akka.Persistence/Snapshot/LocalSnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/LocalSnapshotStore.cs @@ -67,10 +67,6 @@ public LocalSnapshotStore() private readonly ILoggingAdapter _log; - [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) - => LoadAsync(persistenceId, criteria, CancellationToken.None); - /// protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { @@ -85,10 +81,6 @@ protected override Task LoadAsync(string persistenceId, Snapsh return RunWithStreamDispatcher(() => Load(metadata)); } - [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) - => SaveAsync(metadata, snapshot, CancellationToken.None); - /// protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot, CancellationToken cancellationToken) { @@ -100,10 +92,6 @@ protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot, Ca }); } - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteAsync(SnapshotMetadata metadata) - => DeleteAsync(metadata, CancellationToken.None); - /// protected override Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { @@ -121,10 +109,6 @@ protected override Task DeleteAsync(SnapshotMetadata metadata, CancellationToken }); } - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) - => DeleteAsync(persistenceId, criteria, CancellationToken.None); - /// protected override async Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { diff --git a/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs index a3b10200583..41f459086eb 100644 --- a/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/MemorySnapshotStore.cs @@ -27,10 +27,6 @@ public class MemorySnapshotStore : SnapshotStore /// protected virtual List Snapshots { get; } = new(); - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteAsync(SnapshotMetadata metadata) - => DeleteAsync(metadata, CancellationToken.None); - protected override Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { bool Pred(SnapshotEntry x) => x.PersistenceId == metadata.PersistenceId && (metadata.SequenceNr <= 0 || metadata.SequenceNr == long.MaxValue || x.SequenceNr == metadata.SequenceNr) @@ -42,10 +38,6 @@ bool Pred(SnapshotEntry x) => x.PersistenceId == metadata.PersistenceId && (meta return TaskEx.Completed; } - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) - => DeleteAsync(persistenceId, criteria, CancellationToken.None); - protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { var filter = CreateRangeFilter(persistenceId, criteria); @@ -54,10 +46,6 @@ protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCrite return TaskEx.Completed; } - [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) - => LoadAsync(persistenceId, criteria, CancellationToken.None); - protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { var filter = CreateRangeFilter(persistenceId, criteria); @@ -67,10 +55,6 @@ protected override Task LoadAsync(string persistenceId, Snapsh return Task.FromResult(snapshot); } - [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) - => SaveAsync(metadata, snapshot, CancellationToken.None); - protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot, CancellationToken cancellationToken) { diff --git a/src/core/Akka.Persistence/Snapshot/NoSnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/NoSnapshotStore.cs index 91a54484ace..7f66b3ecbc3 100644 --- a/src/core/Akka.Persistence/Snapshot/NoSnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/NoSnapshotStore.cs @@ -61,23 +61,11 @@ protected NoSnapshotStoreException(SerializationInfo info, StreamingContext cont } } - [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) - { - return Task.FromResult((SelectedSnapshot)null); - } - protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria, CancellationToken cancellationToken) { return Task.FromResult((SelectedSnapshot)null); } - [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) - { - return Flop(); - } - /// /// This exception is thrown when no snapshot store is configured. /// @@ -86,12 +74,6 @@ protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot, Ca return Flop(); } - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteAsync(SnapshotMetadata metadata) - { - return Flop(); - } - /// /// This exception is thrown when no snapshot store is configured. /// @@ -100,12 +82,6 @@ protected override Task DeleteAsync(SnapshotMetadata metadata, CancellationToken return Flop(); } - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) - { - return Flop(); - } - /// /// This exception is thrown when no snapshot store is configured. /// diff --git a/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs b/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs index ed4aa5e7cb3..cde611e7700 100644 --- a/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs +++ b/src/core/Akka.Persistence/Snapshot/SnapshotStore.cs @@ -231,18 +231,6 @@ private static Exception TryUnwrapException(Exception e) return e; } - /// - /// Plugin API: Asynchronously loads a snapshot. - /// - /// This call is protected with a circuit-breaker - /// - /// Id of the persistent actor. - /// Selection criteria for loading. - [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract Task LoadAsync( - string persistenceId, - SnapshotSelectionCriteria criteria); - /// /// Plugin API: Asynchronously loads a snapshot. /// @@ -256,18 +244,6 @@ protected abstract Task LoadAsync( SnapshotSelectionCriteria criteria, CancellationToken cancellationToken); - /// - /// Plugin API: Asynchronously saves a snapshot. - /// - /// This call is protected with a circuit-breaker - /// - /// Snapshot metadata. - /// Snapshot. - [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract Task SaveAsync( - SnapshotMetadata metadata, - object snapshot); - /// /// Plugin API: Asynchronously saves a snapshot. /// @@ -281,15 +257,6 @@ protected abstract Task SaveAsync( object snapshot, CancellationToken cancellationToken); - /// - /// Plugin API: Deletes the snapshot identified by . - /// - /// This call is protected with a circuit-breaker - /// - /// Snapshot metadata. - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract Task DeleteAsync(SnapshotMetadata metadata); - /// /// Plugin API: Deletes the snapshot identified by . /// @@ -299,18 +266,6 @@ protected abstract Task SaveAsync( /// used to signal cancelled snapshot operation protected abstract Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken); - /// - /// Plugin API: Deletes all snapshots matching provided . - /// - /// This call is protected with a circuit-breaker - /// - /// Id of the persistent actor. - /// Selection criteria for deleting. - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract Task DeleteAsync( - string persistenceId, - SnapshotSelectionCriteria criteria); - /// /// Plugin API: Deletes all snapshots matching provided . /// diff --git a/src/examples/Akka.Persistence.Custom/Journal/SqliteJournal.cs b/src/examples/Akka.Persistence.Custom/Journal/SqliteJournal.cs index 66d5b14c3e9..a4f9ee50ae2 100644 --- a/src/examples/Akka.Persistence.Custom/Journal/SqliteJournal.cs +++ b/src/examples/Akka.Persistence.Custom/Journal/SqliteJournal.cs @@ -270,10 +270,6 @@ public sealed override async Task ReplayMessagesAsync( } // - [Obsolete("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - public sealed override Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) - => ReadHighestSequenceNrAsync(persistenceId, fromSequenceNr, CancellationToken.None); - // public sealed override async Task ReadHighestSequenceNrAsync( string persistenceId, @@ -302,10 +298,6 @@ public sealed override async Task ReadHighestSequenceNrAsync( } // - [Obsolete("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected sealed override async Task> WriteMessagesAsync(IEnumerable messages) - => await WriteMessagesAsync(messages, CancellationToken.None); - // protected sealed override async Task> WriteMessagesAsync( IEnumerable messages, CancellationToken cancellationToken) @@ -399,10 +391,6 @@ protected sealed override async Task> WriteMessagesAsy } // - [Obsolete("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected sealed override Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) - => DeleteMessagesToAsync(persistenceId, toSequenceNr, CancellationToken.None); - // protected sealed override async Task DeleteMessagesToAsync( string persistenceId, diff --git a/src/examples/Akka.Persistence.Custom/Snapshot/SqliteSnapshotStore.cs b/src/examples/Akka.Persistence.Custom/Snapshot/SqliteSnapshotStore.cs index f50c8d769f2..ab143f7e5a3 100644 --- a/src/examples/Akka.Persistence.Custom/Snapshot/SqliteSnapshotStore.cs +++ b/src/examples/Akka.Persistence.Custom/Snapshot/SqliteSnapshotStore.cs @@ -181,10 +181,6 @@ private bool WaitingForInitialization(object message) } // - [Obsolete("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task LoadAsync(string persistenceId, SnapshotSelectionCriteria criteria) - => LoadAsync(persistenceId, criteria, CancellationToken.None); - // protected sealed override async Task LoadAsync( string persistenceId, @@ -236,10 +232,6 @@ protected sealed override async Task LoadAsync( } // - [Obsolete("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task SaveAsync(SnapshotMetadata metadata, object snapshot) - => SaveAsync(metadata, snapshot, CancellationToken.None); - // protected sealed override async Task SaveAsync( SnapshotMetadata metadata, @@ -311,10 +303,6 @@ protected sealed override async Task SaveAsync( } // - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteAsync(SnapshotMetadata metadata) - => DeleteAsync(metadata, CancellationToken.None); - // protected sealed override async Task DeleteAsync(SnapshotMetadata metadata, CancellationToken cancellationToken) { @@ -357,10 +345,6 @@ protected sealed override async Task DeleteAsync(SnapshotMetadata metadata, Canc } // - [Obsolete("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override Task DeleteAsync(string persistenceId, SnapshotSelectionCriteria criteria) - => DeleteAsync(persistenceId, criteria, CancellationToken.None); - // protected sealed override async Task DeleteAsync( string persistenceId, From 7a5a20dcf70d28f3c5321709df9f9d82df926bc0 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Sat, 10 May 2025 00:04:06 +0700 Subject: [PATCH 10/11] Code cleanup, make sure `AtomicState.Callthrough()` have the same behavior --- src/core/Akka/Util/Internal/AtomicState.cs | 106 ++++++++------------- 1 file changed, 38 insertions(+), 68 deletions(-) diff --git a/src/core/Akka/Util/Internal/AtomicState.cs b/src/core/Akka/Util/Internal/AtomicState.cs index 1e332c62b37..5c556fc18ef 100644 --- a/src/core/Akka/Util/Internal/AtomicState.cs +++ b/src/core/Akka/Util/Internal/AtomicState.cs @@ -77,23 +77,9 @@ await Task /// /// Implementation of the call /// containing the result of the call - public async Task CallThrough(Func> task) - { - var result = default(T); - try - { - result = await task().WaitAsync(_callTimeout).ConfigureAwait(false); - CallSucceeds(); - } - catch (Exception ex) - { - var capturedException = ExceptionDispatchInfo.Capture(ex); - CallFails(capturedException.SourceException); - capturedException.Throw(); - } - - return result; - } + [Obsolete("Use CallThrough that accepts delegate function with CancellationToken argument. Since 1.5.42")] + public Task CallThrough(Func> task) + => CallThrough(_ => task()); /// /// Shared implementation of call across all states. Thrown exception or execution of the call beyond the allowed @@ -104,55 +90,51 @@ public async Task CallThrough(Func> task) public async Task CallThrough(Func> task) { var result = default(T); + var cts = new CancellationTokenSource(); try { - using(var cts = new CancellationTokenSource(_callTimeout)) - result = await task(cts.Token).WaitAsync(cts.Token).ConfigureAwait(false); + result = await task(cts.Token).WaitAsync(_callTimeout).ConfigureAwait(false); CallSucceeds(); } catch (Exception ex) { + cts.Cancel(); // Signal the protected delegate that operation has been canceled var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); } - - return result; - } - - public async Task CallThrough(TState state, Func> task) - { - var result = default(T); - try + finally { - result = await task(state).WaitAsync(_callTimeout).ConfigureAwait(false); - CallSucceeds(); - } - catch (Exception ex) - { - var capturedException = ExceptionDispatchInfo.Capture(ex); - CallFails(capturedException.SourceException); - capturedException.Throw(); + cts.Dispose(); } return result; } + [Obsolete("Use CallThrough that accepts delegate function with CancellationToken argument. Since 1.5.42")] + public Task CallThrough(TState state, Func> task) + => CallThrough(state, (s, _) => task(s)); + public async Task CallThrough(TState state, Func> task) { var result = default(T); + var cts = new CancellationTokenSource(); try { - using(var cts = new CancellationTokenSource(_callTimeout)) - result = await task(state, cts.Token).WaitAsync(cts.Token).ConfigureAwait(false); + result = await task(state, cts.Token).WaitAsync(_callTimeout).ConfigureAwait(false); CallSucceeds(); } catch (Exception ex) { + cts.Cancel(); // Signal the protected delegate that operation has been canceled var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); } + finally + { + cts.Dispose(); + } return result; } @@ -163,20 +145,9 @@ public async Task CallThrough(TState state, Func /// Implementation of the call /// containing the result of the call - public async Task CallThrough(Func task) - { - try - { - await task().WaitAsync(_callTimeout).ConfigureAwait(false); - CallSucceeds(); - } - catch (Exception ex) - { - var capturedException = ExceptionDispatchInfo.Capture(ex); - CallFails(capturedException.SourceException); - capturedException.Throw(); - } - } + [Obsolete("Use CallThrough that accepts delegate function with CancellationToken argument. Since 1.5.42")] + public Task CallThrough(Func task) + => CallThrough(_ => task()); /// /// Shared implementation of call across all states. Thrown exception or execution of the call beyond the allowed @@ -186,49 +157,48 @@ public async Task CallThrough(Func task) /// containing the result of the call public async Task CallThrough(Func task) { + var cts = new CancellationTokenSource(); try { - using(var cts = new CancellationTokenSource(_callTimeout)) - await task(cts.Token).WaitAsync(cts.Token).ConfigureAwait(false); + await task(cts.Token).WaitAsync(_callTimeout).ConfigureAwait(false); CallSucceeds(); } catch (Exception ex) { + cts.Cancel(); // Signal the protected delegate that operation has been canceled var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); } - } - - public async Task CallThrough(TState state, Func task) - { - try - { - await task(state).WaitAsync(_callTimeout).ConfigureAwait(false); - CallSucceeds(); - } - catch (Exception ex) + finally { - var capturedException = ExceptionDispatchInfo.Capture(ex); - CallFails(capturedException.SourceException); - capturedException.Throw(); + cts.Dispose(); } } + [Obsolete("Use CallThrough that accepts delegate function with CancellationToken argument. Since 1.5.42")] + public Task CallThrough(TState state, Func task) + => CallThrough(state, (s, _) => task(s)); + public async Task CallThrough(TState state, Func task) { + var cts = new CancellationTokenSource(); try { - using(var cts = new CancellationTokenSource(_callTimeout)) - await task(state, cts.Token).WaitAsync(cts.Token).ConfigureAwait(false); + await task(state, cts.Token).WaitAsync(_callTimeout).ConfigureAwait(false); CallSucceeds(); } catch (Exception ex) { + cts.Cancel(); // Signal the protected delegate that operation has been canceled var capturedException = ExceptionDispatchInfo.Capture(ex); CallFails(capturedException.SourceException); capturedException.Throw(); } + finally + { + cts.Dispose(); + } } /// From 19e73dfc69c41e9e879f3e6caa12a8800407cdf9 Mon Sep 17 00:00:00 2001 From: Gregorius Soedharmo Date: Sat, 10 May 2025 02:10:44 +0700 Subject: [PATCH 11/11] Update API Approval list --- ...pec.ApprovePersistence.DotNet.verified.txt | 53 ------------------- ...PISpec.ApprovePersistence.Net.verified.txt | 53 ------------------- 2 files changed, 106 deletions(-) diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.DotNet.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.DotNet.verified.txt index 7261fde8c63..d56d0a2edd9 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.DotNet.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.DotNet.verified.txt @@ -857,22 +857,13 @@ namespace Akka.Persistence.Journal { protected readonly bool CanPublish; protected AsyncWriteJournal() { } - [System.ObsoleteAttribute("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Sinc" + - "e 1.5.42")] - protected abstract System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr); protected abstract System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken); - [System.ObsoleteAttribute("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead." + - " Since 1.5.42")] - public abstract System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); public abstract System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken); protected virtual bool Receive(object message) { } protected virtual bool ReceivePluginInternal(object message) { } protected bool ReceiveWriteJournal(object message) { } public abstract System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback); protected static System.Exception TryUnwrapException(System.Exception e) { } - [System.ObsoleteAttribute("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1" + - ".5.42")] - protected abstract System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages); protected abstract System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken); } public abstract class AsyncWriteProxy : Akka.Persistence.Journal.AsyncWriteJournal, Akka.Actor.IActorStash, Akka.Actor.IWithUnboundedStash, Akka.Actor.IWithUnrestrictedStash, Akka.Dispatch.IRequiresMessageQueue @@ -966,9 +957,6 @@ namespace Akka.Persistence.Journal } public interface IAsyncRecovery { - [System.ObsoleteAttribute("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead." + - " Since 1.5.42")] - System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken); System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback); } @@ -1000,22 +988,13 @@ namespace Akka.Persistence.Journal protected virtual System.Collections.Concurrent.ConcurrentDictionary> Messages { get; } public System.Collections.Generic.IDictionary> Add(Akka.Persistence.IPersistentRepresentation persistent) { } public System.Collections.Generic.IDictionary> Delete(string pid, long seqNr) { } - [System.ObsoleteAttribute("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Sinc" + - "e 1.5.42")] - protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) { } protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken) { } public long HighestSequenceNr(string pid) { } public System.Collections.Generic.IEnumerable Read(string pid, long fromSeqNr, long toSeqNr, long max) { } - [System.ObsoleteAttribute("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead." + - " Since 1.5.42")] - public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) { } public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken) { } protected override bool ReceivePluginInternal(object message) { } public override System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback) { } public System.Collections.Generic.IDictionary> Update(string pid, long seqNr, System.Func updater) { } - [System.ObsoleteAttribute("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1" + - ".5.42")] - protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages) { } protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken) { } public sealed class CurrentPersistenceIds : Akka.Event.IDeadLetterSuppression { @@ -1187,21 +1166,13 @@ namespace Akka.Persistence.Snapshot public class LocalSnapshotStore : Akka.Persistence.Snapshot.SnapshotStore { public LocalSnapshotStore() { } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } protected System.IO.FileInfo GetSnapshotFileForWrite(Akka.Persistence.SnapshotMetadata metadata, string extension = "") { } - [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } protected override void PreStart() { } protected override bool ReceivePluginInternal(object message) { } protected virtual void Save(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } - [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } protected void Serialize(System.IO.Stream stream, Akka.Persistence.Serialization.Snapshot snapshot) { } protected System.IO.FileInfo WithOutputStream(Akka.Persistence.SnapshotMetadata metadata, System.Action p) { } @@ -1210,33 +1181,17 @@ namespace Akka.Persistence.Snapshot { public MemorySnapshotStore() { } protected virtual System.Collections.Generic.List Snapshots { get; } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } } public sealed class NoSnapshotStore : Akka.Persistence.Snapshot.SnapshotStore { public NoSnapshotStore() { } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } public class NoSnapshotStoreException : System.Exception { @@ -1258,19 +1213,11 @@ namespace Akka.Persistence.Snapshot public abstract class SnapshotStore : Akka.Actor.ActorBase { protected SnapshotStore() { } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata); protected abstract System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken); - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria); protected abstract System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken); - [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria); protected abstract System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken); protected virtual bool Receive(object message) { } protected virtual bool ReceivePluginInternal(object message) { } - [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot); protected abstract System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken); } } \ No newline at end of file diff --git a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.Net.verified.txt b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.Net.verified.txt index 6741f90b061..a136e19d3d9 100644 --- a/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.Net.verified.txt +++ b/src/core/Akka.API.Tests/verify/CoreAPISpec.ApprovePersistence.Net.verified.txt @@ -857,22 +857,13 @@ namespace Akka.Persistence.Journal { protected readonly bool CanPublish; protected AsyncWriteJournal() { } - [System.ObsoleteAttribute("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Sinc" + - "e 1.5.42")] - protected abstract System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr); protected abstract System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken); - [System.ObsoleteAttribute("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead." + - " Since 1.5.42")] - public abstract System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); public abstract System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken); protected virtual bool Receive(object message) { } protected virtual bool ReceivePluginInternal(object message) { } protected bool ReceiveWriteJournal(object message) { } public abstract System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback); protected static System.Exception TryUnwrapException(System.Exception e) { } - [System.ObsoleteAttribute("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1" + - ".5.42")] - protected abstract System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages); protected abstract System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken); } public abstract class AsyncWriteProxy : Akka.Persistence.Journal.AsyncWriteJournal, Akka.Actor.IActorStash, Akka.Actor.IWithUnboundedStash, Akka.Actor.IWithUnrestrictedStash, Akka.Dispatch.IRequiresMessageQueue @@ -966,9 +957,6 @@ namespace Akka.Persistence.Journal } public interface IAsyncRecovery { - [System.ObsoleteAttribute("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead." + - " Since 1.5.42")] - System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr); System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken); System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback); } @@ -1000,22 +988,13 @@ namespace Akka.Persistence.Journal protected virtual System.Collections.Concurrent.ConcurrentDictionary> Messages { get; } public System.Collections.Generic.IDictionary> Add(Akka.Persistence.IPersistentRepresentation persistent) { } public System.Collections.Generic.IDictionary> Delete(string pid, long seqNr) { } - [System.ObsoleteAttribute("Use DeleteMessagesToAsync() that takes a CancellationToken argument instead. Sinc" + - "e 1.5.42")] - protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr) { } protected override System.Threading.Tasks.Task DeleteMessagesToAsync(string persistenceId, long toSequenceNr, System.Threading.CancellationToken cancellationToken) { } public long HighestSequenceNr(string pid) { } public System.Collections.Generic.IEnumerable Read(string pid, long fromSeqNr, long toSeqNr, long max) { } - [System.ObsoleteAttribute("Use ReadHighestSequenceNrAsync() that takes a CancellationToken argument instead." + - " Since 1.5.42")] - public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr) { } public override System.Threading.Tasks.Task ReadHighestSequenceNrAsync(string persistenceId, long fromSequenceNr, System.Threading.CancellationToken cancellationToken) { } protected override bool ReceivePluginInternal(object message) { } public override System.Threading.Tasks.Task ReplayMessagesAsync(Akka.Actor.IActorContext context, string persistenceId, long fromSequenceNr, long toSequenceNr, long max, System.Action recoveryCallback) { } public System.Collections.Generic.IDictionary> Update(string pid, long seqNr, System.Func updater) { } - [System.ObsoleteAttribute("Use WriteMessagesAsync() that takes a CancellationToken argument instead. Since 1" + - ".5.42")] - protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages) { } protected override System.Threading.Tasks.Task> WriteMessagesAsync(System.Collections.Generic.IEnumerable messages, System.Threading.CancellationToken cancellationToken) { } public sealed class CurrentPersistenceIds : Akka.Event.IDeadLetterSuppression { @@ -1185,21 +1164,13 @@ namespace Akka.Persistence.Snapshot public class LocalSnapshotStore : Akka.Persistence.Snapshot.SnapshotStore { public LocalSnapshotStore() { } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } protected System.IO.FileInfo GetSnapshotFileForWrite(Akka.Persistence.SnapshotMetadata metadata, string extension = "") { } - [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } protected override void PreStart() { } protected override bool ReceivePluginInternal(object message) { } protected virtual void Save(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } - [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } protected void Serialize(System.IO.Stream stream, Akka.Persistence.Serialization.Snapshot snapshot) { } protected System.IO.FileInfo WithOutputStream(Akka.Persistence.SnapshotMetadata metadata, System.Action p) { } @@ -1208,33 +1179,17 @@ namespace Akka.Persistence.Snapshot { public MemorySnapshotStore() { } protected virtual System.Collections.Generic.List Snapshots { get; } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } } public sealed class NoSnapshotStore : Akka.Persistence.Snapshot.SnapshotStore { public NoSnapshotStore() { } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata) { } protected override System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria) { } protected override System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken) { } - [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot) { } protected override System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken) { } public class NoSnapshotStoreException : System.Exception { @@ -1256,19 +1211,11 @@ namespace Akka.Persistence.Snapshot public abstract class SnapshotStore : Akka.Actor.ActorBase { protected SnapshotStore() { } - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata); protected abstract System.Threading.Tasks.Task DeleteAsync(Akka.Persistence.SnapshotMetadata metadata, System.Threading.CancellationToken cancellationToken); - [System.ObsoleteAttribute("Use DeleteAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria); protected abstract System.Threading.Tasks.Task DeleteAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken); - [System.ObsoleteAttribute("Use LoadAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria); protected abstract System.Threading.Tasks.Task LoadAsync(string persistenceId, Akka.Persistence.SnapshotSelectionCriteria criteria, System.Threading.CancellationToken cancellationToken); protected virtual bool Receive(object message) { } protected virtual bool ReceivePluginInternal(object message) { } - [System.ObsoleteAttribute("Use SaveAsync() that takes a CancellationToken argument instead. Since 1.5.42")] - protected abstract System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot); protected abstract System.Threading.Tasks.Task SaveAsync(Akka.Persistence.SnapshotMetadata metadata, object snapshot, System.Threading.CancellationToken cancellationToken); } } \ No newline at end of file