akkadotnet / akka.net

Canonical actor model implementation for .NET with local + distributed actors in C# and F#.
http://getakka.net
Other
4.71k stars 1.04k forks source link

Enhancement: create ActorTaskScheduler overload that schedules Task to dispatcher without blocking current actor #4363

Open Aaronontheweb opened 4 years ago

Aaronontheweb commented 4 years ago

Version: 1.4.3 and later

An advanced feature - right now we support the ability to schedule a Task onto the current actor's dispatcher using the ActorTaskScheduler:

https://github.com/akkadotnet/akka.net/blob/03341fc2e2157620abf5986473faa5f235723ca4/src/core/Akka/Dispatch/ActorTaskScheduler.cs#L130-L164

One of the side effects of this method is that it blocks the current actor in order to run that Task.

I think it'd be worthwhile to add an overload that allows a task to be scheduled onto the current dispatcher, without impacting the current actor's ability to process its mailbox. That could make for some interesting scenarios in areas like IOT, where users often need to run actors on pinned or dedicated thread dispatchers.

yesh-nadella commented 4 years ago

If I understand it right, the feature to schedule a task without suspending the mailbox needs to be implemented. Would the new overloaded method need to take in an optional behavior parameter to become stacked? This is in case if the actor only wants to process certain kinds of messages while the task is running.

Aaronontheweb commented 4 years ago

@yesh-nadella I wouldn't bother with the second part - I'd leave it at "scheduler on the same dispatcher as me but don't block me"

swimmesberger commented 2 years ago

@Aaronontheweb I would really like a feature like that. We often have cases were we have actors where we have async sequences of commands, most of the time these commands wait for something external to happen (e.g. some IO message from the network). So some of those async methods can take multiple seconds. But we also want to support querying of the state of the actor (e.g. progress). In this case something like:

Receive<Messages.Req>(r => {
    MyAsyncMethod().PipeTo(Sender, Self);
});

private async Task<string> MyAsyncMethod(Messages.Req) {
....
}

can be done. But the same thing can be expressed like that too:

ReceiveAsync<Messages.Req>(async r => {
     var resp = await MyAsyncMethod(r);
     Sender.Tell(resp);
});

private async Task<string> MyAsyncMethod(Messages.Req) {
....
}

with the distinction that the first thing allows user-messages while processing the task and the second does not. By integrating this behaviour into an enum and putting it in the ReceiveAsync API the intent can be much clearer documented.