This is a common scenario I run into, where I have two (or more) actors getting some data asynchronously, and then I need to do an operation when they're all finished.
What is the common pattern to do this?
Here's a simplified example.
public MasterActor : ReceiveActor
{
public MasterActor()
{
Initialize();
}
public void Initiaize()
{
Receive<DoSomeWork>(_ =>
{
var actor1 = Context.ActorOf(Props.Create(() => new Actor1());
var actor2 = Context.ActorOf(Props.Create(() => new Actor2());
// pretend these actors send responses to their senders
// for sake of example each of these methods take between 1 and 3 seconds
actor1.Tell(new GetActor1Data());
actor2.Tell(new GetActor2Data());
});
Receive<Actor1Response>(m =>
{
//actor 1 has finished it's work
});
Receive<Actor2Response>(m =>
{
//actor 2 has finished it's work
});
}
}
To kick this off I send the MasterActor
a DoSomeWork
message.
What is the common way to do an operation when I have both a Actor1Response
and an Actor2Response
.
I don't really want to have logic in each receive handler checking if the other one is finished or anything like that. I guess what i'm thinking of something similar to a Task.WaitAll()
method.
Am I just attacking the problem the wrong way? Do I need to re-write the actors in a different way?
Any common patterns or solutions would be awesome.
The common solution for that is attaching some kind of correlation id shared by both request and response messages - since actor processes messages synchronously, this could be unchecked int/long counter.
You simply store correlation ids in some data structure (let say set) inside the caller, and when response is received, remove it's correlation id from set. WaitAll
finishes basically when set is empty or timeout occurs.
You can set timeout by using Context.SetReceiveTimeout(timeout)
, this way actor will send a ReceiveTimeout
method to itself after it haven't received any message for some time.
This behavior is pretty generic and may be abstracted quite easily.
The simplest way to do this would be to increment a "vote" count on the master when each child replies. When vote == child count, you're done.
You could extend this so as to only count the first message from each child, or a specific message from each child, but it all boils down to counting in the end.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With