I have an actor with many children and I am querying it to get an aggregate of the data in its children. This operation could take a few seconds.
I was about to do this and it feels so completely wrong. The handle method is called by an Ask<>
.
public void Handle(Message message)
{
var children = Context.GetChildren();
var tasks = new List<Task<Result>>();
foreach (var child in children)
{
var t = child.Ask<Result>(new Query);
tasks.Add(t);
}
Task.WaitAll(tasks.ToArray()); // Gah!
// do some work
Sender.Tell(new Response(new Results()));
}
I have a few ideas, but wanted to get some input as I don't really want to reinvent a 20 sided wheel.
I am worried about the reference to Sender
and what it will be pointing at when I finally get to call Tell
on it as it is a static call.
I've ended up using the Task.WhenAll
continuation, but still not convinced it's the right Akka way - which is the point here. I can make it work, I just want to know the best practice options.
In general Ask
should be used only for the communication with an actor from external services, almost never between two actors. It's a lot more expensive than using Tell
. Additional problem is to use Task.WaitAll
which actually blocks current thread until all responses will arrive, which is also bad for performance and may end up with deadlock.
Similar thread was already discussed on github.
General solution for aggregation problems is:
- Create a separate actor for aggregation process.
- Initialize it with list of actors, it is supposed to collect data from and remember the actor, which will be informed with collected result.
- Send request/query for each actor.
- Handle each request/query response, aggregating it in separate data structure and remove a sender from the list of awaited actors.
- Once there is no actor to await for - send a result and stop current actor (the one responsible for data aggregation).
- Attach
ReceiveTimeout
mechanism in case, when for some reason not all actors are able to respond in reasonable time - when timeout will hit, you may return failure or list of responses collected so far.
PS: Don't use TypedActor - it's also bad for performance and is/will become obsoleted.