From 0af123aa6d09de93dec188a5656c3e4cbff78a0d Mon Sep 17 00:00:00 2001 From: Roland Date: Thu, 30 May 2013 12:44:08 +0200 Subject: [PATCH] only create the routees once they can be looked-up, see #3406 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - move the creation of the RoutedActorCell’s route into ActorCell.start(); it used to be done in the constructor - this requires “val route” to turn into a volatile private var Thanks to Patrik for finding it! --- .../akka/routing/RouteeCreationSpec.scala | 51 +++++++++++++++++++ .../scala/akka/actor/dungeon/Dispatch.scala | 2 +- .../src/main/scala/akka/routing/Routing.scala | 16 ++++-- 3 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 akka-actor-tests/src/test/scala/akka/routing/RouteeCreationSpec.scala diff --git a/akka-actor-tests/src/test/scala/akka/routing/RouteeCreationSpec.scala b/akka-actor-tests/src/test/scala/akka/routing/RouteeCreationSpec.scala new file mode 100644 index 0000000000..85a76fee57 --- /dev/null +++ b/akka-actor-tests/src/test/scala/akka/routing/RouteeCreationSpec.scala @@ -0,0 +1,51 @@ +/** + * Copyright (C) 2009-2013 Typesafe Inc. + */ + +package akka.routing + +import akka.testkit.AkkaSpec +import akka.actor.Props +import akka.actor.Actor +import akka.actor.ActorRef +import akka.actor.LocalActorRef +import scala.concurrent.duration._ + +class RouteeCreationSpec extends AkkaSpec { + + "Creating Routees" must { + + "result in visible routees" in { + val N = 100 + system.actorOf(Props(new Actor { + testActor ! system.actorFor(self.path) + def receive = Actor.emptyBehavior + }).withRouter(RoundRobinRouter(N))) + for (i ← 1 to N) { + expectMsgType[ActorRef] match { + case _: LocalActorRef ⇒ // fine + case x ⇒ fail(s"routee $i was a ${x.getClass}") + } + } + } + + "allow sending to context.parent" in { + val N = 100 + system.actorOf(Props(new Actor { + context.parent ! "one" + def receive = { + case "one" ⇒ testActor forward "two" + } + }).withRouter(RoundRobinRouter(N))) + val gotit = receiveWhile(messages = N) { + case "two" ⇒ lastSender.toString + } + expectNoMsg(100.millis) + if (gotit.size != N) { + fail(s"got only ${gotit.size} from \n${gotit mkString "\n"}") + } + } + + } + +} diff --git a/akka-actor/src/main/scala/akka/actor/dungeon/Dispatch.scala b/akka-actor/src/main/scala/akka/actor/dungeon/Dispatch.scala index a17383fefc..6ae063d9f6 100644 --- a/akka-actor/src/main/scala/akka/actor/dungeon/Dispatch.scala +++ b/akka-actor/src/main/scala/akka/actor/dungeon/Dispatch.scala @@ -74,7 +74,7 @@ private[akka] trait Dispatch { this: ActorCell ⇒ /** * Start this cell, i.e. attach it to the dispatcher. */ - final def start(): this.type = { + def start(): this.type = { // This call is expected to start off the actor by scheduling its mailbox. dispatcher.attach(this) this diff --git a/akka-actor/src/main/scala/akka/routing/Routing.scala b/akka-actor/src/main/scala/akka/routing/Routing.scala index 3e5b3d137d..b3436133e5 100644 --- a/akka-actor/src/main/scala/akka/routing/Routing.scala +++ b/akka-actor/src/main/scala/akka/routing/Routing.scala @@ -46,7 +46,7 @@ private[akka] object RoutedActorCell { } } -private[akka] class RoutedActorCell(_system: ActorSystemImpl, _ref: InternalActorRef, _props: Props, _supervisor: InternalActorRef) +private[akka] final class RoutedActorCell(_system: ActorSystemImpl, _ref: InternalActorRef, _props: Props, _supervisor: InternalActorRef) extends ActorCell( _system, _ref, @@ -67,7 +67,11 @@ private[akka] class RoutedActorCell(_system: ActorSystemImpl, _ref: InternalActo private var _routeeProvider: RouteeProvider = _ def routeeProvider = _routeeProvider - val route = { + @volatile + private var _route: Route = _ + def route = _route + + private def startRoute() { val routeeProps = _props.withRouter(NoRouter) _routeeProvider = routerConfig.createRouteeProvider(this, routeeProps) val r = routerConfig.createRoute(routeeProvider) @@ -76,7 +80,13 @@ private[akka] class RoutedActorCell(_system: ActorSystemImpl, _ref: InternalActo if (resizer.isTimeForResize(resizeCounter.getAndIncrement())) resizer.resize(routeeProvider) } - r + _route = r + } + + override def start(): this.type = { + startRoute() + // create the routees before scheduling the Router actor + super.start() } /*