AKKA- how to block the creation of an actor if its name is not uniqe in the cluster

360 views Asked by At

I'm trying to block the possibility of having actors in the system that are sharing the same name(they are on different paths so InvalidActorNameException will not be thrown)

application.conf:

someactor {
  akka.remote.netty.tcp.port = 6405
  akka.cluster.auto-down-unreachable-after = 20s
  akka.cluster.seed-nodes = ["akka.tcp://[email protected]:2552"]
  akka.actor.provider = "akka.cluster.ClusterActorRefProvider"
}

Main:

object SomeActor extends App {
  val system  =  ActorSystem("mySys", ConfigFactory.load("application").getConfig("someactor"))
  val t = system.actorOf(Props(classOf[SomeActor]), "someActor")
}

Actor:

class SomeActor extends Actor {
    val cluster = Cluster(SomeActor.system)
    override def receive = {
       case x=> println(x)
    }
}

If you run the application once with the 6405 port and once with 6406 port then the application will work, but I want it to notice that the system already contains an actor with the name "someActor" and block that call.

I don't mind adding the name as the role or to other config if it will be able to block by that but I can't have a state like a map containing the already existing names(or an actor containing the map with message passing) or to have a long running operation like actorSelection(and in any case they won't be safe if actorOf is called from multiple places in parallel).

2

There are 2 answers

0
user_s On BEST ANSWER

I managed to do it with Cluster Aware Router of type group(each actor will run on remote node). The role of the node is the name "someActor" , I'm initializing the actor on the remote node with the same name "someActor"(so I'll know what the path to this actor) and router totalInstances config equal to 1(so only one node will be part of the router)

Router init:

context.actorOf(
        ClusterRouterGroup(RoundRobinGroup(Nil), ClusterRouterGroupSettings(
          totalInstances = 1, routeesPaths = List("/user/someActor"),
          allowLocalRoutees = false, useRole = Some("someActor"))).props()

The remote actor:

object RemoteActor extends App{
  val system = ActorSystem("mySys",ConfigFactory.load("remoteActorConfig"))
  system.actorOf(Props[RemoteActor], "someActor")

}

class RemoteActor extends Actor with ActorLogging{
  override def receive: Receive = {
    case x =>
      log.info(s"got: $x}")
  }
}

and the remoteActorConfig :

akka{
  remote.netty.tcp.port = 0
  cluster.auto-down-unreachable-after = 20s
  cluster.seed-nodes = ["akka.tcp://[email protected]:2552"]
  cluster.roles.1 = "someActor"
  actor.provider = "akka.cluster.ClusterActorRefProvider"
}

Now if I'll run twice RemoteActor, run the app that initialize the router and send a broadcast message to the router- only one actor RemoterActor will receive it (and always the same one).

1
XGoVoid On

If you really need 100% non overlapping UUIDs why don't you just create a single service for UUID assignment and get your UUID before you create the actor?

You could also use a SHA hash on the hostname, port, and actor name and an incrementing worker number per actor.

You could also set up a Cluster Router for the workers and akka would do all that for you and you would only have to send to one ActorRef to access the worker pool.