diff --git a/akka-cluster/src/main/resources/reference.conf b/akka-cluster/src/main/resources/reference.conf index 7094397f00..a2311f596a 100644 --- a/akka-cluster/src/main/resources/reference.conf +++ b/akka-cluster/src/main/resources/reference.conf @@ -121,10 +121,10 @@ akka { # 25 members. max-nr-of-instances-per-node = 1 - # Defines if routees are to be deployed on the same node as the head router - # actor, or only on remote nodes. + # Defines if routees are allowed to be located on the same node as + # the head router actor, or only on remote nodes. # Useful for master-worker scenario where all routees are remote. - deploy-on-own-node = on + routees-on-own-node = on # Actor path of the routees to lookup with actorFor on the member # nodes in the cluster. E.g. "/user/myservice". If this isn't defined diff --git a/akka-cluster/src/main/scala/akka/cluster/ClusterActorRefProvider.scala b/akka-cluster/src/main/scala/akka/cluster/ClusterActorRefProvider.scala index e2824daffc..17e7cc0515 100644 --- a/akka-cluster/src/main/scala/akka/cluster/ClusterActorRefProvider.scala +++ b/akka-cluster/src/main/scala/akka/cluster/ClusterActorRefProvider.scala @@ -43,7 +43,7 @@ private[akka] class ClusterDeployer(_settings: ActorSystem.Settings, _pm: Dynami val clusterRouterSettings = ClusterRouterSettings( totalInstances = deploy.config.getInt("nr-of-instances"), maxInstancesPerNode = deploy.config.getInt("cluster.max-nr-of-instances-per-node"), - deployOnOwnNode = deploy.config.getBoolean("cluster.deploy-on-own-node"), + routeesOnOwnNode = deploy.config.getBoolean("cluster.routees-on-own-node"), routeesPath = deploy.config.getString("cluster.routees-path")) Some(deploy.copy( diff --git a/akka-cluster/src/main/scala/akka/cluster/routing/ClusterRouterConfig.scala b/akka-cluster/src/main/scala/akka/cluster/routing/ClusterRouterConfig.scala index 74b890ce7a..fa45341519 100644 --- a/akka-cluster/src/main/scala/akka/cluster/routing/ClusterRouterConfig.scala +++ b/akka-cluster/src/main/scala/akka/cluster/routing/ClusterRouterConfig.scala @@ -71,9 +71,14 @@ case class ClusterRouterConfig(local: RouterConfig, settings: ClusterRouterSetti case class ClusterRouterSettings( totalInstances: Int, - maxInstancesPerNode: Int, - deployOnOwnNode: Boolean, - routeesPath: String) { + maxInstancesPerNode: Int = 1, + routeesOnOwnNode: Boolean = true, + routeesPath: String = "") { + + if (totalInstances <= 0) throw new IllegalArgumentException("totalInstances of cluster router must be > 0") + if (maxInstancesPerNode <= 0) throw new IllegalArgumentException("maxInstancesPerNode of cluster router must be > 0") + if (isRouteesPathDefined && maxInstancesPerNode != 1) + throw new IllegalArgumentException("maxInstancesPerNode of cluster router must be 1 when routeesPath is defined") def isRouteesPathDefined: Boolean = ((routeesPath ne null) && routeesPath != "") } @@ -131,7 +136,7 @@ private[akka] class ClusterRouteeProvider( val currentNodes = availbleNodes if (currentRoutees.size >= settings.totalInstances) { None - } else if (currentNodes.isEmpty && settings.deployOnOwnNode) { + } else if (currentNodes.isEmpty && settings.routeesOnOwnNode) { // use my own node, cluster information not updated yet Some(cluster.selfAddress) } else { @@ -163,7 +168,7 @@ private[akka] class ClusterRouteeProvider( } private[routing] def isAvailble(m: Member): Boolean = { - m.status == MemberStatus.Up && (settings.deployOnOwnNode || m.address != cluster.selfAddress) + m.status == MemberStatus.Up && (settings.routeesOnOwnNode || m.address != cluster.selfAddress) } } @@ -219,24 +224,29 @@ private[akka] class ClusterRouterActor extends Router { /** * Sugar to define cluster aware router programatically. - * Usage Java API: + * Java API. + * When creating and deploying routees: * [[[ * context.actorOf(ClusterRouterPropsDecorator.decorate(new Props(MyActor.class), - * new RoundRobinRouter(0), 10, 2, true), "myrouter"); + * new RoundRobinRouter(0), 10, 2), "myrouter"); + * ]]] + * When looking up routees: + * [[[ + * context.actorOf(ClusterRouterPropsDecorator.decorate(new Props(MyActor.class), + * new RoundRobinRouter(0), 10, "/user/myservice"), "myrouter"); * ]]] * * Corresponding for Scala API is found in [[akka.cluster.routing.ClusterRouterProps]]. * */ object ClusterRouterPropsDecorator { - def decorate(props: Props, router: RouterConfig, totalInstances: Int, maxInstancesPerNode: Int, - deployOnOwnNode: Boolean): Props = { - props.withClusterRouter(router, totalInstances, maxInstancesPerNode, deployOnOwnNode) - } + def decorate(props: Props, router: RouterConfig, totalInstances: Int, maxInstancesPerNode: Int): Props = + decorate(props, router, ClusterRouterSettings(totalInstances, maxInstancesPerNode)) - def decorate(props: Props, router: RouterConfig, totalInstances: Int, maxInstancesPerNode: Int, - deployOnOwnNode: Boolean, routeesPath: String): Props = { - props.withClusterRouter(router, totalInstances, maxInstancesPerNode, deployOnOwnNode, routeesPath) - } + def decorate(props: Props, router: RouterConfig, totalInstances: Int, routeesPath: String): Props = + decorate(props, router, ClusterRouterSettings(totalInstances, routeesPath = routeesPath)) + + def decorate(props: Props, router: RouterConfig, settings: ClusterRouterSettings): Props = + props.withClusterRouter(router, settings) } diff --git a/akka-cluster/src/main/scala/akka/cluster/routing/package.scala b/akka-cluster/src/main/scala/akka/cluster/routing/package.scala index ece0d5d8ce..f16c6e839b 100644 --- a/akka-cluster/src/main/scala/akka/cluster/routing/package.scala +++ b/akka-cluster/src/main/scala/akka/cluster/routing/package.scala @@ -13,30 +13,34 @@ package object routing { /** * Sugar to define cluster aware router programatically. - * Usage Scala API: + * + * When creating and deploying routees: * [[[ * import akka.cluster.routing.ClusterRouterProps * context.actorOf(Props[SomeActor].withClusterRouter(RoundRobinRouter(), - * totalInstances = 10, maxInstancesPerNode = 2, deployOnOwnNode = true), "myrouter") + * totalInstances = 10, maxInstancesPerNode = 2), "myrouter") + * ]]] + * + * When looking up routees: + * [[[ + * import akka.cluster.routing.ClusterRouterProps + * context.actorOf(Props[SomeActor].withClusterRouter(RoundRobinRouter(), + * totalInstances = 10, routeesPath = "/user/myservice"), "myrouter") * ]]] * * Corresponding for Java API is found in [[akka.cluster.routing.ClusterRouterPropsDecorator]]. */ implicit class ClusterRouterProps(val props: Props) extends AnyVal { - /* - * Without this helper it would look as ugly as: - * val router = RoundRobinRouter(nrOfInstances = 10) - * val actor = system.actorOf(Props[SomeActor].withRouter(router).withDeploy( - * Deploy(routerConfig = ClusterRouterConfig(router, totalInstances = router.nrOfInstances, maxInstancesPerNode = 2, - * deployOnOwnNode = true))), "myrouter") - */ + def withClusterRouter(router: RouterConfig, totalInstances: Int, maxInstancesPerNode: Int): Props = + withClusterRouter(router, ClusterRouterSettings(totalInstances, maxInstancesPerNode)) - def withClusterRouter(router: RouterConfig, totalInstances: Int, maxInstancesPerNode: Int, - deployOnOwnNode: Boolean = true, routeesPath: String = ""): Props = { + def withClusterRouter(router: RouterConfig, totalInstances: Int, routeesPath: String): Props = + withClusterRouter(router, ClusterRouterSettings(totalInstances, routeesPath = routeesPath)) + + def withClusterRouter(router: RouterConfig, settings: ClusterRouterSettings): Props = { props.withRouter(router).withDeploy( - Deploy(routerConfig = ClusterRouterConfig(router, - ClusterRouterSettings(totalInstances, maxInstancesPerNode, deployOnOwnNode, routeesPath)))) + Deploy(routerConfig = ClusterRouterConfig(router, settings))) } } diff --git a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/ClusterRoundRobinRoutedActorSpec.scala b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/ClusterRoundRobinRoutedActorSpec.scala index b291e48579..8ad38b1264 100644 --- a/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/ClusterRoundRobinRoutedActorSpec.scala +++ b/akka-cluster/src/multi-jvm/scala/akka/cluster/routing/ClusterRoundRobinRoutedActorSpec.scala @@ -60,7 +60,7 @@ object ClusterRoundRobinRoutedActorMultiJvmSpec extends MultiNodeConfig { cluster { enabled = on max-nr-of-instances-per-node = 1 - deploy-on-own-node = off + routees-on-own-node = off } } /router4 { @@ -68,7 +68,6 @@ object ClusterRoundRobinRoutedActorMultiJvmSpec extends MultiNodeConfig { nr-of-instances = 10 cluster { enabled = on - max-nr-of-instances-per-node = 2 routees-path = "/user/myservice" } } @@ -92,7 +91,7 @@ abstract class ClusterRoundRobinRoutedActorSpec extends MultiNodeSpec(ClusterRou lazy val router2 = { import akka.cluster.routing.ClusterRouterProps system.actorOf(Props[SomeActor].withClusterRouter(RoundRobinRouter(), - totalInstances = 3, maxInstancesPerNode = 1, deployOnOwnNode = true), "router2") + totalInstances = 3, maxInstancesPerNode = 1), "router2") } lazy val router3 = system.actorOf(Props[SomeActor].withRouter(RoundRobinRouter()), "router3") lazy val router4 = system.actorOf(Props[SomeActor].withRouter(RoundRobinRouter()), "router4") @@ -206,7 +205,7 @@ abstract class ClusterRoundRobinRoutedActorSpec extends MultiNodeSpec(ClusterRou enterBarrier("after-5") } - "deploy routees to only remote nodes when deploy-on-own-node = off" taggedAs LongRunningTest in { + "deploy routees to only remote nodes when routees-on-own-node = off" taggedAs LongRunningTest in { runOn(first) { val iterationCount = 10 diff --git a/akka-cluster/src/test/scala/akka/cluster/ClusterDeployerSpec.scala b/akka-cluster/src/test/scala/akka/cluster/ClusterDeployerSpec.scala index 251f58ab90..a966e61fcd 100644 --- a/akka-cluster/src/test/scala/akka/cluster/ClusterDeployerSpec.scala +++ b/akka-cluster/src/test/scala/akka/cluster/ClusterDeployerSpec.scala @@ -14,12 +14,18 @@ object ClusterDeployerSpec { val deployerConf = ConfigFactory.parseString(""" akka.actor.provider = "akka.cluster.ClusterActorRefProvider" akka.actor.deployment { - /user/service2 { + /user/service1 { router = round-robin nr-of-instances = 20 cluster.enabled = on cluster.max-nr-of-instances-per-node = 3 - cluster.deploy-on-own-node = off + cluster.routees-on-own-node = off + } + /user/service2 { + router = round-robin + nr-of-instances = 20 + cluster.enabled = on + cluster.routees-on-own-node = off cluster.routees-path = "/user/myservice" } } @@ -37,7 +43,20 @@ class ClusterDeployerSpec extends AkkaSpec(ClusterDeployerSpec.deployerConf) { "A RemoteDeployer" must { - "be able to parse 'akka.actor.deployment._' with specified cluster settings" in { + "be able to parse 'akka.actor.deployment._' with specified cluster lookup routee settings" in { + val service = "/user/service1" + val deployment = system.asInstanceOf[ActorSystemImpl].provider.deployer.lookup(service.split("/").drop(1)) + deployment must not be (None) + + deployment must be(Some( + Deploy( + service, + deployment.get.config, + ClusterRouterConfig(RoundRobinRouter(20), ClusterRouterSettings(20, 3, false, "")), + ClusterScope))) + } + + "be able to parse 'akka.actor.deployment._' with specified cluster deploy routee settings" in { val service = "/user/service2" val deployment = system.asInstanceOf[ActorSystemImpl].provider.deployer.lookup(service.split("/").drop(1)) deployment must not be (None) @@ -46,7 +65,7 @@ class ClusterDeployerSpec extends AkkaSpec(ClusterDeployerSpec.deployerConf) { Deploy( service, deployment.get.config, - ClusterRouterConfig(RoundRobinRouter(20), ClusterRouterSettings(20, 3, false, "/user/myservice")), + ClusterRouterConfig(RoundRobinRouter(20), ClusterRouterSettings(20, 1, false, "/user/myservice")), ClusterScope))) }