2018-10-29 17:19:37 +08:00
|
|
|
/*
|
2019-01-02 18:55:26 +08:00
|
|
|
* Copyright (C) 2017-2019 Lightbend Inc. <https://www.lightbend.com>
|
2017-06-26 16:03:06 +02:00
|
|
|
*/
|
2018-04-24 16:03:55 +01:00
|
|
|
|
2017-06-26 16:03:06 +02:00
|
|
|
package akka.cluster.singleton
|
|
|
|
|
|
|
|
|
|
import scala.concurrent.duration._
|
|
|
|
|
|
|
|
|
|
import com.typesafe.config.ConfigFactory
|
|
|
|
|
|
|
|
|
|
import akka.actor.{ Actor, ActorLogging, Address, PoisonPill, Props }
|
|
|
|
|
import akka.cluster.Cluster
|
|
|
|
|
|
|
|
|
|
import akka.testkit.ImplicitSender
|
|
|
|
|
import akka.remote.testkit.{ MultiNodeConfig, MultiNodeSpec, STMultiNodeSpec }
|
2017-06-26 15:03:33 +02:00
|
|
|
import akka.cluster.ClusterSettings
|
2017-06-26 16:03:06 +02:00
|
|
|
|
2017-07-04 17:11:21 +02:00
|
|
|
object MultiDcSingletonManagerSpec extends MultiNodeConfig {
|
2017-06-26 16:03:06 +02:00
|
|
|
val controller = role("controller")
|
|
|
|
|
val first = role("first")
|
|
|
|
|
val second = role("second")
|
|
|
|
|
val third = role("third")
|
|
|
|
|
|
|
|
|
|
commonConfig(ConfigFactory.parseString("""
|
|
|
|
|
akka.actor.provider = "cluster"
|
|
|
|
|
akka.actor.serialize-creators = off
|
|
|
|
|
akka.remote.log-remote-lifecycle-events = off"""))
|
|
|
|
|
|
2017-06-26 16:28:44 +02:00
|
|
|
nodeConfig(controller) {
|
|
|
|
|
ConfigFactory.parseString("""
|
2017-07-12 11:47:32 +01:00
|
|
|
akka.cluster.multi-data-center.self-data-center = one
|
2017-06-26 16:28:44 +02:00
|
|
|
akka.cluster.roles = []""")
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-26 16:03:06 +02:00
|
|
|
nodeConfig(first) {
|
2017-06-26 16:28:44 +02:00
|
|
|
ConfigFactory.parseString("""
|
2017-07-12 11:47:32 +01:00
|
|
|
akka.cluster.multi-data-center.self-data-center = one
|
2017-06-26 16:28:44 +02:00
|
|
|
akka.cluster.roles = [ worker ]""")
|
|
|
|
|
}
|
|
|
|
|
nodeConfig(second, third) {
|
|
|
|
|
ConfigFactory.parseString("""
|
2017-07-12 11:47:32 +01:00
|
|
|
akka.cluster.multi-data-center.self-data-center = two
|
2017-06-26 16:28:44 +02:00
|
|
|
akka.cluster.roles = [ worker ]""")
|
2017-06-26 16:03:06 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-04 17:11:21 +02:00
|
|
|
class MultiDcSingletonManagerMultiJvmNode1 extends MultiDcSingletonManagerSpec
|
|
|
|
|
class MultiDcSingletonManagerMultiJvmNode2 extends MultiDcSingletonManagerSpec
|
|
|
|
|
class MultiDcSingletonManagerMultiJvmNode3 extends MultiDcSingletonManagerSpec
|
|
|
|
|
class MultiDcSingletonManagerMultiJvmNode4 extends MultiDcSingletonManagerSpec
|
2017-06-26 16:03:06 +02:00
|
|
|
|
2017-07-04 17:11:21 +02:00
|
|
|
class MultiDcSingleton extends Actor with ActorLogging {
|
|
|
|
|
import MultiDcSingleton._
|
2017-06-26 16:03:06 +02:00
|
|
|
|
|
|
|
|
val cluster = Cluster(context.system)
|
|
|
|
|
|
|
|
|
|
override def receive: Receive = {
|
2019-02-09 15:25:39 +01:00
|
|
|
case Ping =>
|
2017-07-12 11:47:32 +01:00
|
|
|
sender() ! Pong(cluster.settings.SelfDataCenter, cluster.selfAddress, cluster.selfRoles)
|
2017-06-26 16:03:06 +02:00
|
|
|
}
|
|
|
|
|
}
|
2017-07-04 17:11:21 +02:00
|
|
|
object MultiDcSingleton {
|
2017-06-26 16:03:06 +02:00
|
|
|
case object Ping
|
2017-07-04 17:11:21 +02:00
|
|
|
case class Pong(fromDc: String, fromAddress: Address, roles: Set[String])
|
2017-06-26 16:03:06 +02:00
|
|
|
}
|
|
|
|
|
|
2019-03-11 10:38:24 +01:00
|
|
|
abstract class MultiDcSingletonManagerSpec
|
|
|
|
|
extends MultiNodeSpec(MultiDcSingletonManagerSpec)
|
|
|
|
|
with STMultiNodeSpec
|
|
|
|
|
with ImplicitSender {
|
2017-07-04 17:11:21 +02:00
|
|
|
import MultiDcSingletonManagerSpec._
|
2017-06-26 16:03:06 +02:00
|
|
|
|
|
|
|
|
override def initialParticipants = roles.size
|
|
|
|
|
|
|
|
|
|
val cluster = Cluster(system)
|
|
|
|
|
cluster.join(node(controller).address)
|
|
|
|
|
enterBarrier("nodes-joined")
|
|
|
|
|
|
|
|
|
|
val worker = "worker"
|
|
|
|
|
|
2017-07-04 17:11:21 +02:00
|
|
|
"A SingletonManager in a multi data center cluster" must {
|
|
|
|
|
"start a singleton instance for each data center" in {
|
2017-06-26 16:03:06 +02:00
|
|
|
|
|
|
|
|
runOn(first, second, third) {
|
2019-03-13 10:56:20 +01:00
|
|
|
system.actorOf(
|
|
|
|
|
ClusterSingletonManager
|
|
|
|
|
.props(Props[MultiDcSingleton](), PoisonPill, ClusterSingletonManagerSettings(system).withRole(worker)),
|
|
|
|
|
"singletonManager")
|
2017-06-26 16:03:06 +02:00
|
|
|
}
|
|
|
|
|
|
2019-03-11 10:38:24 +01:00
|
|
|
val proxy = system.actorOf(
|
|
|
|
|
ClusterSingletonProxy.props("/user/singletonManager", ClusterSingletonProxySettings(system).withRole(worker)))
|
2017-06-26 16:03:06 +02:00
|
|
|
|
|
|
|
|
enterBarrier("managers-started")
|
|
|
|
|
|
2017-07-04 17:11:21 +02:00
|
|
|
proxy ! MultiDcSingleton.Ping
|
2017-09-04 13:21:34 +02:00
|
|
|
val pong = expectMsgType[MultiDcSingleton.Pong](20.seconds)
|
2017-06-26 16:03:06 +02:00
|
|
|
|
|
|
|
|
enterBarrier("pongs-received")
|
|
|
|
|
|
2017-07-12 11:47:32 +01:00
|
|
|
pong.fromDc should equal(Cluster(system).settings.SelfDataCenter)
|
2017-06-26 16:03:06 +02:00
|
|
|
pong.roles should contain(worker)
|
|
|
|
|
runOn(controller, first) {
|
2017-07-04 17:11:21 +02:00
|
|
|
pong.roles should contain(ClusterSettings.DcRolePrefix + "one")
|
2017-06-26 16:03:06 +02:00
|
|
|
}
|
|
|
|
|
runOn(second, third) {
|
2017-07-04 17:11:21 +02:00
|
|
|
pong.roles should contain(ClusterSettings.DcRolePrefix + "two")
|
2017-06-26 16:03:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enterBarrier("after-1")
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-04 17:11:21 +02:00
|
|
|
"be able to use proxy across different data centers" in {
|
2017-06-26 16:28:44 +02:00
|
|
|
runOn(third) {
|
2019-03-11 10:38:24 +01:00
|
|
|
val proxy = system.actorOf(
|
2019-03-13 10:56:20 +01:00
|
|
|
ClusterSingletonProxy.props(
|
|
|
|
|
"/user/singletonManager",
|
|
|
|
|
ClusterSingletonProxySettings(system).withRole(worker).withDataCenter("one")))
|
2017-07-04 17:11:21 +02:00
|
|
|
proxy ! MultiDcSingleton.Ping
|
|
|
|
|
val pong = expectMsgType[MultiDcSingleton.Pong](10.seconds)
|
|
|
|
|
pong.fromDc should ===("one")
|
2017-06-26 16:28:44 +02:00
|
|
|
pong.roles should contain(worker)
|
2017-07-04 17:11:21 +02:00
|
|
|
pong.roles should contain(ClusterSettings.DcRolePrefix + "one")
|
2017-06-26 16:28:44 +02:00
|
|
|
}
|
|
|
|
|
enterBarrier("after-1")
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-26 16:03:06 +02:00
|
|
|
}
|
|
|
|
|
}
|