Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to get all instantiated actors currently available on a given node in Akka.NET

I have the following code in my application which creates an instance of an Akka.NET actor in my cluster as such:

_actorSystem = ActorSystem.Create("mycluster");
_actoraActor = this._actorSystem.ActorOf<ActorA>();

Note that I deliberately omit the name property as I intend to create N actors of type ActorA and don't want to manage the names. Running the above I end up with an actor which has an ID that looks like this:

akka://mycluster/user/$a#1293118665

The problem I run into is trying to determine the Actor path from a different node. So for example I have tried doing the following:

public class ActorB : ReceiveActor
{
    private readonly Cluster Cluster = Akka.Cluster.Cluster.Get(Context.System);


    public ActorB()
    {

        this.Receive<ActorIdentity>(this.IdentifyMessageReceived);
        this.ReceiveAsync<ClusterEvent.MemberUp>(this.MemberUpReceived);
    }

    protected override void PreStart()
    {
        this.Cluster.Subscribe(this.Self, ClusterEvent.InitialStateAsEvents, new[]
        {
            typeof(ClusterEvent.IMemberEvent),
            typeof(ClusterEvent.UnreachableMember)                
        });
    }

    protected override void PostStop()
    {
        this.Cluster.Unsubscribe(this.Self);
    }

    private async Task<bool> MemberUpReceived(ClusterEvent.MemberUp obj)
    {
        if (obj.Member.HasRole("actora"))
        {
            //!The problem is here.
            //ALL YOU ARE PROVIDED IS THE NODE ADDRESS:  
            //Obviously this makes sense because it's the node that has come alive
            //and not the instances themselves.

            string address = obj.Member.Address.ToString();
            //akka.tcp://mycluster@localhost:666
            Context.ActorSelection(address).Tell(new Identify(1));
        }

        return true;
    }

    private bool IdentifyMessageReceived(ActorIdentity obj)
    {
        return true;
    }
}

Where via leveraging of the cluster MEMBER-UP event I try to send an Identify request to the new member but the problem I run into is the ClusterEvent.MemberUp object provided does not contain information regarding the actors within the node but only appears to contain a node reference that looks like this:

akka.tcp://mycluster@localhost:666

Which makes perfect sense because its the node that has come online, not an actor.

If I change my code to use a named actor:

_actorSystem = ActorSystem.Create("mycluster");
_actoraActor = this._actorSystem.ActorOf<ActorA>("actora");

I can then successfully query the service how I need. This is what you would expect when you have a named actor but there appears to be no way to actually externally determine instances of running actors on a node.

So, when using N instances of unnamed actors what are the correct steps to identify references to the actors you are interested in, specifically when the actors have been generated without a name?

EDIT:

I've decided to restate the question because I didn't adequately describe it initially. The correct expression of this question is:

"Is there a way to get all instantiated actors currently available on a given node from a external actor when all you have is the node path?"

To me it just seems like this should be something built into the base framework UNLESS there is some sort of design consideration that I don't fully understand.

I also note that I think it's likely the correct approach to my particular problem might just be that I am trying to do a Pub/Sub and this https://getakka.net/articles/clustering/distributed-publish-subscribe.html is more appropriate.

like image 666
Maxim Gershkovich Avatar asked Jun 25 '18 16:06

Maxim Gershkovich


1 Answers

I think for your purposes here you should consider leveraging the actor hierarchy.

Instead of creating a top-level actor with a randomly assigned name, create a parent with a hard-coded name:

_actorSystem = ActorSystem.Create("mycluster");
_delegatorParent = this._actorSystem.ActorOf<ParentActorA>("parent");

This parent actor can spawn any number of children, and it can spawn children in response to incoming messages:

_delegatorParent.Tell(new WorkItem("someWork", 1200));

This could cause the parent to create a child actor that actually executes the work:

public class ParentActorA{
    public ParentActorA(){
       Receive<WorkItem>(x => {
          // create new child to carry out the work
          var delegatorActor = Context.ActorOf<ActorA>();
          delegatorActor.Forward(x);
       });
    }
}

This gives you a fixed entry point into this node / family of actors while still having the ability to spin up new actors that don't have specific names. Just look up the parent with the static name, not the children who execute the work.

While you're at it you may also want to take a look at pool routers and the child per entity pattern in Akka.NET.

like image 98
Aaronontheweb Avatar answered Oct 23 '22 17:10

Aaronontheweb