Search code examples
javaakkaakka-cluster

Akka ActorSelection over a whole cluser


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.


Solution

  • 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());