Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Akka.net waiting for multiple pieces of data

Tags:

c#

actor

akka.net

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.

like image 752
Kyle Gobel Avatar asked Oct 28 '15 18:10

Kyle Gobel


2 Answers

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.

like image 156
Bartosz Sypytkowski Avatar answered Oct 26 '22 16:10

Bartosz Sypytkowski


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.

like image 42
Morgan Skinner Avatar answered Oct 26 '22 16:10

Morgan Skinner