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?
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.