I am using Akka 2.5 with Java 9. I am testing different ways to start up a cluster. I am not using routing. I would like to know if there a simple way to initialize a cluster node’s role name with the same string that was used to create the corresponding ActorRef in the node’s actor system.
Let’s say I have a non-actor java application that spins up a cluster of two actor system nodes with roles named “A” and “B” as defined in application.conf:
In each case, an actor listens to the node that came up:`
public class AkkaTestClusterListener extends AbstractActor
{
private String nodeRole;
...
/** Subscribe to cluster events. */
@Override
public Receive createReceive()
{
return receiveBuilder().match(MemberUp.class, this::processMemberUpEevent).build();
}
private void processMemberUpEevent(MemberUp mUp)
{
Member member = mUp.member();
Option scOpt = member.address().port();
// convert from scala.Option<Object> type to java.util.Optional<Integer>
Optional<Integer> optional = Optional.ofNullable((Integer) scOpt.getOrElse(null));
assert optional != null;
// the following works ok but it smells-
// obtain the role of the node using the member's detected port number as defined in application.conf
int port = optional.get().intValue();
switch (port)
{
case 6111:
this.nodeRole = "A";
break;
case 6112:
this.nodeRole = "B";
break;
default:
this.nodeRole = "NOT_SET";
break;
}
}
I’m not quite sure I understand the question, but, you assign the node roles in the config during start up, like you show in application.conf, and then you can access it through the cluster extension, like so:
But when each node comes up and processMemberUpEevent(MemberUp mUp) is called by AkkaTestClusterListener.createReceive() I have no way of knowing if it was called for node “A” or for node “B”.
Sure I can access the roles Set as you suggest, but that just gives me a set of all the roles. It doesn’t tell me which actor system (actorSystemA or actorSystemB) was started, even though I named each top ActorRef “A” or “B” when they were created.
Cluster node roles are a set to allow nodes to have many roles. In your configuration all nodes will have both roles A and B. If you want just node 1 to be in role A and just node 2 to be in role B you must start the node with the corresponding configuration.
Usually that would be for deployment so it’d be different config files, or passed in by setting system properties or environment variables when starting the JVM with the node. You can do it programatically as well, like so:
// load application.conf
final Config applicationConf = ConfigFactory.load();
// override some config programmtically
final Map<String, Object> properties = new HashMap<>();
properties.put("akka.cluster.roles", Arrays.asList("A", "seed"));
final Config programmaticOverrides = ConfigFactory.parseMap(properties);
final Config config = programmaticOverrides.withFallback(applicationConf);
final ActorSystem system = ActorSystem.create("my-system", config);
final Cluster cluster = Cluster.get(system);
cluster.join(cluster.selfAddress());
system.log().info("I got roles: {}", cluster.getSelfRoles());
Thanks for the explanation.
Should it still possible in this situation to require both nodes “A” and “B” to be up by setting property
akka.cluster.role { seed.min-nr-of-members = 2 }
for the cluster to be up? (doesn’t seem to work for me).
As long as you also have the role seed as well as your roles A and B, that will make the cluster not see the nodes as up until there are at least two of them with that role. This can easiest be observed by either enabling debug logging for Akka and look at the logs, or subscribe to the MemberUp cluster event.