Enumerating available actors in Akka.NET cluster

560 Views Asked by At

I have two actors, lets call them ActorA and ActorB. Both actors reside in their own separate process as a Topshelf based Windows Service.

Basically they look like this.

public class ActorA : ReceiveActor
{
    public ActorA()
    {
        this.Receive<ActorIdentity>(this.IdentifyMessageReceived);
    }


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

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"))
        {
            IActorRef actorSelection = await Context.ActorSelection("akka.tcp://mycluster@localhost:666/user/actora").ResolveOne(TimeSpan.FromSeconds(1));
            actorSelection.Tell(new Identify(1));
        }

        return true;
    }

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

My config files are super simple

ActorA:

akka {
    log-config-on-start = on
    stdout-loglevel = DEBUG
    loglevel = DEBUG
    actor.provider = cluster
    remote {
        dot-netty.tcp {
            port = 666
            hostname = localhost

        }
    }
    cluster {
        seed-nodes = ["akka.tcp://mycluster@localhost:666"]
        roles = [actora]
    }
}

ActorB:

akka {
    log-config-on-start = on
    stdout-loglevel = DEBUG
    loglevel = DEBUG
    actor.provider = cluster
    remote {
        dot-netty.tcp {
            port = 0
            hostname = localhost
        }
    }
    cluster {
        seed-nodes = ["akka.tcp://mycluster@localhost:666"]
        roles = [actorb]
    }
}

I now want to identify all the given actors attached to my cluster. I do this by waiting for the cluster node MEMBER UP event and trying to send an Identify() message to the given actor to receive a reference to it.

The problem is that I cannot seem to be able to successfully send the message back to ActorA. Infact when executing the above code (despite the fact that I have the correct reference in the ActorSelection method) the ActorIdentity message is invoked in ActorB rather than ActorA.

I have tried handling all received message in ActorA and it appears I never receive the Identity message. However I can successfully send any other type of message ActorA using the same ActorSelection reference.

So can anyone provide any insight? Why is my identity message never reaching my target actor?

1

There are 1 best solutions below

1
On BEST ANSWER

ActorIdentity message is invoked in ActorB rather than ActorA.

This works as intended, as you're sending Identify request from actor B → A, for which ActorIdentity is a response message (send automatically from A → B).

You can already observe this behavior in action, since:

Context.ActorSelection(path).ResolveOne(timeout)

is more or less an equivalent of

Context.ActorSelection(path).Ask<ActorIdentity>(new Identify(null), timeout: timeout)

Identify is a system message, which is handled always before any programmer-defined message handlers are invoked - for this reason you probably won't catch it in your own handlers.