0
votes

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?

1
How can you know that the singleton actor is not started? Maybe you need to implemente preStart and add some logs to know if it's happening or not.hveiga
There is no need to explicitly start singleton provided by akka. The akka implementation monitors cluster state itself and starts singleton on the oldest node which has a role specified for singleton. From the log message you provided, it seems like singleton actually started. To monitor and log cluster state you need to implement something like thisandrey.feoktistov
@andrey.feoktistov I can't understand how actor can be started on the node where is no needed dependencies and properties. On first node (seed) i have simple members monitor (like in given link) and other node with singleton implementation I use akka-persistence and databases in singleton actorandrey.ladniy
@andrey.ladniy Hope that I catch your point. On your seed node you should just start a singleton proxy. In general, the SingletonManager should be created on those nodes that should be able to host your singleton actor implementation and the SingletonProxy on those that should just talk to singleton, but do not host it. In this case, nodes which use the SingletonProxy may know nothing about the singleton actor implementation.andrey.feoktistov
@andrey.feoktistov Almost got it, but I don't need Singleton on the first seed node, it used only on the second node. So I have no SingletonProxy (I fact this is name to ref coordinator) on seed node, but only on the seconde node, and if second node make as a seed, all works fine. I try implement simple app for issue example.andrey.ladniy

1 Answers

1
votes

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
  }

  // ...
}