I have a simple cluster with a service actor named "service" on each node. This service is respectively exposed with ClusterClientRecptionist
to be able to use ist from outside the cluster with ClusterClient
.
A client then registers users, which are created on random nodes of the cluster (because the ClusterClient
dispatches randomly). For example /user/service/user1
on node1 and /user/service/user2
on node2.
What I want to do now, is to send a message to all registered users, independently of their physical location. I thout that was easy by using an ActorSelection
like /user/service/*
. But this only resolves local acotrs on the corresponding node.
I work with Java by the way.
Option 1
I just solved it by using the DistributedPubSubMediator
as described in this question and documented here.
private ActorRef mediator = DistributedPubSub.get(getContext().system()).mediator();
@Override
public void onReceive(Object msg) throws Exception {
String msgStr = msg.toString();
String val = msgStr.substring(4);
if (msgStr.startsWith("add")) {
ActorRef act = context().actorOf(Props.create(User.class, val), val);
// subscribe the newly created user on topic "allUsers"
mediator.tell(new DistributedPubSubMediator.Subscribe("allUsers", act), self());
System.out.println("user created: " + act);
} else if (msgStr.startsWith("say")) {
// broadcast text message to all subscribed users
mediator.tell(new DistributedPubSubMediator.Publish("allUsers", new Text(val)), self());
}
}
Option 2
A second successful option is by using a BroadcastGroup router. Important is that the clustering is enabled in configuration:
akka.actor.deployment {
/allUsers {
router = broadcast-group
routees.paths = ["/user/service/*"]
cluster {
enabled = on
allow-local-routees = on
}
}
}
Afterwards, it can be used straightforward as documented.
ActorRef allUsers = system.actorOf(FromConfig.getInstance().props(), "allUsers");
[...]
allUsers.tell(new Text(val), self());