Test consistent hashing router with cluster router, see #944
* Found and fixed issue with NoRouter which is used in the combination of FromConfig and cluster.enabled=true * Multi-node test that tests several of the possible cominations
This commit is contained in:
parent
9423d37da9
commit
bc34adf624
2 changed files with 183 additions and 1 deletions
|
|
@ -205,7 +205,7 @@ case class ConsistentHashingRouter(
|
|||
* that can't be defined in configuration.
|
||||
*/
|
||||
override def withFallback(other: RouterConfig): RouterConfig = other match {
|
||||
case _: FromConfig ⇒ this
|
||||
case _: FromConfig | _: NoRouter ⇒ this
|
||||
case otherRouter: ConsistentHashingRouter ⇒
|
||||
val useResizer =
|
||||
if (this.resizer.isEmpty && otherRouter.resizer.isDefined) otherRouter.resizer
|
||||
|
|
|
|||
|
|
@ -0,0 +1,182 @@
|
|||
/**
|
||||
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
package akka.cluster.routing
|
||||
|
||||
import scala.concurrent.Await
|
||||
import scala.concurrent.util.duration._
|
||||
|
||||
import com.typesafe.config.ConfigFactory
|
||||
|
||||
import akka.actor.Actor
|
||||
import akka.actor.ActorRef
|
||||
import akka.actor.Address
|
||||
import akka.actor.Props
|
||||
import akka.cluster.MultiNodeClusterSpec
|
||||
import akka.pattern.ask
|
||||
import akka.remote.testkit.MultiNodeConfig
|
||||
import akka.remote.testkit.MultiNodeSpec
|
||||
import akka.routing.ConsistentHashingRouter
|
||||
import akka.routing.ConsistentHashingRouter.ConsistentHashMapping
|
||||
import akka.routing.ConsistentHashingRouter.ConsistentHashableEnvelope
|
||||
import akka.routing.CurrentRoutees
|
||||
import akka.routing.FromConfig
|
||||
import akka.routing.RouterRoutees
|
||||
import akka.testkit._
|
||||
|
||||
object ClusterConsistentHashingRouterMultiJvmSpec extends MultiNodeConfig {
|
||||
|
||||
class Echo extends Actor {
|
||||
def receive = {
|
||||
case _ ⇒ sender ! self
|
||||
}
|
||||
}
|
||||
|
||||
val first = role("first")
|
||||
val second = role("second")
|
||||
val third = role("third")
|
||||
|
||||
commonConfig(debugConfig(on = false).
|
||||
withFallback(ConfigFactory.parseString("""
|
||||
common-router-settings = {
|
||||
router = consistent-hashing
|
||||
nr-of-instances = 10
|
||||
cluster {
|
||||
enabled = on
|
||||
max-nr-of-instances-per-node = 2
|
||||
}
|
||||
}
|
||||
|
||||
akka.actor.deployment {
|
||||
/router1 = ${common-router-settings}
|
||||
/router3 = ${common-router-settings}
|
||||
/router4 = ${common-router-settings}
|
||||
}
|
||||
""")).
|
||||
withFallback(MultiNodeClusterSpec.clusterConfig))
|
||||
|
||||
}
|
||||
|
||||
class ClusterConsistentHashingRouterMultiJvmNode1 extends ClusterConsistentHashingRouterSpec
|
||||
class ClusterConsistentHashingRouterMultiJvmNode2 extends ClusterConsistentHashingRouterSpec
|
||||
class ClusterConsistentHashingRouterMultiJvmNode3 extends ClusterConsistentHashingRouterSpec
|
||||
|
||||
abstract class ClusterConsistentHashingRouterSpec extends MultiNodeSpec(ClusterConsistentHashingRouterMultiJvmSpec)
|
||||
with MultiNodeClusterSpec
|
||||
with ImplicitSender with DefaultTimeout {
|
||||
import ClusterConsistentHashingRouterMultiJvmSpec._
|
||||
|
||||
lazy val router1 = system.actorOf(Props[Echo].withRouter(FromConfig()), "router1")
|
||||
|
||||
def currentRoutees(router: ActorRef) =
|
||||
Await.result(router ? CurrentRoutees, remaining).asInstanceOf[RouterRoutees].routees
|
||||
|
||||
/**
|
||||
* Fills in self address for local ActorRef
|
||||
*/
|
||||
private def fullAddress(actorRef: ActorRef): Address = actorRef.path.address match {
|
||||
case Address(_, _, None, None) ⇒ cluster.selfAddress
|
||||
case a ⇒ a
|
||||
}
|
||||
|
||||
"A cluster router with a consistent hashing router" must {
|
||||
"start cluster with 2 nodes" taggedAs LongRunningTest in {
|
||||
awaitClusterUp(first, second)
|
||||
enterBarrier("after-1")
|
||||
}
|
||||
|
||||
"create routees from configuration" in {
|
||||
runOn(first) {
|
||||
awaitCond {
|
||||
// it may take some time until router receives cluster member events
|
||||
currentRoutees(router1).size == 4
|
||||
}
|
||||
currentRoutees(router1).map(fullAddress).toSet must be(Set(address(first), address(second)))
|
||||
}
|
||||
enterBarrier("after-2")
|
||||
}
|
||||
|
||||
"select destination based on hashKey" in {
|
||||
runOn(first) {
|
||||
router1 ! ConsistentHashableEnvelope(message = "A", hashKey = "a")
|
||||
val destinationA = expectMsgType[ActorRef]
|
||||
router1 ! ConsistentHashableEnvelope(message = "AA", hashKey = "a")
|
||||
expectMsg(destinationA)
|
||||
}
|
||||
enterBarrier("after-2")
|
||||
}
|
||||
|
||||
"deploy routees to new member nodes in the cluster" taggedAs LongRunningTest in {
|
||||
|
||||
awaitClusterUp(first, second, third)
|
||||
|
||||
runOn(first) {
|
||||
awaitCond {
|
||||
// it may take some time until router receives cluster member events
|
||||
currentRoutees(router1).size == 6
|
||||
}
|
||||
currentRoutees(router1).map(fullAddress).toSet must be(roles.map(address).toSet)
|
||||
}
|
||||
|
||||
enterBarrier("after-3")
|
||||
}
|
||||
|
||||
"deploy programatically defined routees to the member nodes in the cluster" taggedAs LongRunningTest in {
|
||||
runOn(first) {
|
||||
val router2 = system.actorOf(Props[Echo].withRouter(ClusterRouterConfig(local = ConsistentHashingRouter(),
|
||||
settings = ClusterRouterSettings(totalInstances = 10, maxInstancesPerNode = 2))), "router2")
|
||||
awaitCond {
|
||||
// it may take some time until router receives cluster member events
|
||||
currentRoutees(router2).size == 6
|
||||
}
|
||||
currentRoutees(router2).map(fullAddress).toSet must be(roles.map(address).toSet)
|
||||
}
|
||||
|
||||
enterBarrier("after-4")
|
||||
}
|
||||
|
||||
"handle combination of configured router and programatically defined hashMapping" taggedAs LongRunningTest in {
|
||||
runOn(first) {
|
||||
def hashMapping: ConsistentHashMapping = {
|
||||
case s: String ⇒ s
|
||||
}
|
||||
|
||||
val router3 = system.actorOf(Props[Echo].withRouter(ConsistentHashingRouter(hashMapping = hashMapping)), "router3")
|
||||
|
||||
assertHashMapping(router3)
|
||||
}
|
||||
|
||||
enterBarrier("after-5")
|
||||
}
|
||||
|
||||
"handle combination of configured router and programatically defined hashMapping and ClusterRouterConfig" taggedAs LongRunningTest in {
|
||||
runOn(first) {
|
||||
def hashMapping: ConsistentHashMapping = {
|
||||
case s: String ⇒ s
|
||||
}
|
||||
|
||||
val router4 = system.actorOf(Props[Echo].withRouter(ClusterRouterConfig(
|
||||
local = ConsistentHashingRouter(hashMapping = hashMapping),
|
||||
settings = ClusterRouterSettings(totalInstances = 10, maxInstancesPerNode = 1))), "router4")
|
||||
|
||||
assertHashMapping(router4)
|
||||
}
|
||||
|
||||
enterBarrier("after-6")
|
||||
}
|
||||
|
||||
def assertHashMapping(router: ActorRef): Unit = {
|
||||
awaitCond {
|
||||
// it may take some time until router receives cluster member events
|
||||
currentRoutees(router).size == 6
|
||||
}
|
||||
currentRoutees(router).map(fullAddress).toSet must be(roles.map(address).toSet)
|
||||
|
||||
router ! "a"
|
||||
val destinationA = expectMsgType[ActorRef]
|
||||
router ! "a"
|
||||
expectMsg(destinationA)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue