andrey.ladniy
andrey.ladniy

Reputation: 1674

What is the right way for Akka cluster Singleton startup

I try implement scenario for akka cluster startup:

  1. Run cluster seed with simple actor (cluster monitor, which shows joins of other members)
  2. Run some cluster member, which uses ClusterSingletonManager and ClusterSingletonProxy actors for Singleton implementation

But I have a problem:

10:52:41.691UTC INFO  akka.tcp://[email protected]:9401/user/singletonOfEvents - ClusterSingletonManager state change [Start -> Younger]

and my singleton is not started.

I saw "The singleton actor is always running on the oldest member with specified role." in Akka Cluster Singleton doc. But I can not understand how singleton must be started. Maybe all singletons must be implemented and started in the first seed-node?

Upvotes: 0

Views: 2458

Answers (1)

Leo C
Leo C

Reputation: 22439

As described in Akka documentation, the Cluster Singleton actor instance is started and maintained by the ClusterSingletonManager actor on each of the cluster nodes with the specified role for the singleton. ClusterSingletonManager maintains at most one singleton instance on the oldest node of the cluster with the specified role at any point in time. Should the oldest node (could be the 1st seed node) fail, the next oldest node will be elected. To access the cluster singleton actor, use ClusterSingletonProxy which is present on all nodes with the specified role.

Here's what a sample app that starts the Cluster Singleton might look like:

object Main {

  def workTimeout = 10.seconds

  def main(args: Array[String]): Unit = {
    // Validate arguments host and port from args(0) and args(1)
    // ...

    val role = "worker"

    val conf = ConfigFactory.parseString(s"akka.cluster.roles=[$role]").
      withFallback(ConfigFactory.parseString("akka.remote.netty.tcp.hostname=" + host)).
      withFallback(ConfigFactory.parseString("akka.remote.netty.tcp.port=" + port)).
      withFallback(ConfigFactory.load())

    val system = ActorSystem("ClusterSystem", conf)

    system.actorOf(
      ClusterSingletonManager.props(
        Master.props(workTimeout),
        PoisonPill,
        ClusterSingletonManagerSettings(system).withRole(role)
      ),
      name = "master"
    )

    val singletonAgent = system.actorOf(
      ClusterSingletonProxy.props(
        singletonManagerPath = "/user/master",
        settings = ClusterSingletonProxySettings(system).withRole(role)
      ),
      name = "proxy"
    )

    // ...
  }

  // ...
}

object Master {
  def props(workTimeout: FiniteDuration): Props =
    Props(classOf[Master], workTimeout)

  // ...
}

class Master(workTimeout: FiniteDuration) extends Actor  {
  import Master._

  // ...
}

The cluster configurations might look like the following:

akka {

  actor.provider = "akka.cluster.ClusterActorRefProvider"

  remote.netty.tcp.port = 0
  remote.netty.tcp.hostname = 127.0.0.1

  cluster {
    seed-nodes = [
      "akka.tcp://[email protected]:2552",
      "akka.tcp://[email protected]:2552"
    ]

    auto-down-unreachable-after = 10s
  }

  // ...
}

Upvotes: 1

Related Questions