You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hi, we are using latest Akka 1.3.14 version with target framework both net462 and netcoreapp2.2
There is a problem in asynchronous command handlers when using certain operations (Persist, PersistAsync, Become, BecomeStacked, SetReceiveTimeout) in the continuation after await. Exception thrown states
System.NotSupportedException: There is no active ActorContext, this is most likely due to use of async operations from within this actor.
The problem is that static property ActorBase.Context (called by all affected operations) uses internally ThreadStatic field not resistant to thread switches on continuation.
I managed to simulate the issue reliably with using await task.ConfigureAwait(false). I think that theoretically issue may arise also without using ConfigureAwait(false), since pure await does not guarantee that continuation will run on the same thread, thus preserving ThreadStatic value.
So far we have solved the problem by creating custom base actor class inheriting from ReceivePersistentActor, which captures internally its Context and overwrites implementation of affected operations by wrapping them in ActorCell.UseThreadContext(action).
I have attached a code snippet from our integration tests project showing the issue.
[Fact]
public async Task SaveOk()
{
// ARRANGE
var actorRef = ActorSystem.ActorOf(Props.Create(() => new AsyncHandlingActor("SaveActor")), "SaveActor");
// ACT
var result = await actorRef.Ask<bool>(new Save("data"), TimeSpan.FromSeconds(5));
// ASSERT
Assert.True(result);
// failed on timeout since Persist crashed
}
// actor
public sealed class AsyncHandlingActor : ReceivePersistentActor
{
public override string PersistenceId { get; }
private HashSet<string> State { get; }
public AsyncHandlingActor(string persistenceId)
{
PersistenceId = persistenceId;
State = new HashSet<string>();
Recover<Saved>(saved => { State.Add(saved.Item); });
Recover<SnapshotOffer>(snapshot =>
{
// snapshotting not used
});
CommandAsync<Save>(async save =>
{
var sender = Sender;
await Task.Delay(10).ConfigureAwait(false);
Persist(new Saved(save.Item), saved =>
{
State.Add(saved.Item);
sender.Tell(true);
});
});
}
}
// events
[MessagePackObject]
[Manifest("CommandAsyncIssues_Saved")]
public sealed class Saved
{
[SerializationConstructor]
public Saved(string item)
{
Item = item;
}
[Key(0)]
public string Item { get; }
}
// commands
public sealed class Save
{
public Save(string item)
{
Item = item;
}
public string Item { get; }
}
The text was updated successfully, but these errors were encountered:
Hi, we are using latest Akka 1.3.14 version with target framework both net462 and netcoreapp2.2
There is a problem in asynchronous command handlers when using certain operations (Persist, PersistAsync, Become, BecomeStacked, SetReceiveTimeout) in the continuation after await. Exception thrown states
The problem is that static property ActorBase.Context (called by all affected operations) uses internally ThreadStatic field not resistant to thread switches on continuation.
I managed to simulate the issue reliably with using
await task.ConfigureAwait(false)
. I think that theoretically issue may arise also without using ConfigureAwait(false), since pure await does not guarantee that continuation will run on the same thread, thus preserving ThreadStatic value.So far we have solved the problem by creating custom base actor class inheriting from ReceivePersistentActor, which captures internally its Context and overwrites implementation of affected operations by wrapping them in ActorCell.UseThreadContext(action).
I have attached a code snippet from our integration tests project showing the issue.
The text was updated successfully, but these errors were encountered: