Don't stop dynamic router when all routees terminated, see #2734
This commit is contained in:
parent
3ee42dbe11
commit
accdd63e7d
5 changed files with 39 additions and 6 deletions
|
|
@ -100,6 +100,26 @@ class RoutingSpec extends AkkaSpec(RoutingSpec.config) with DefaultTimeout with
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"not terminate when resizer is used" in {
|
||||||
|
val latch = TestLatch(1)
|
||||||
|
val resizer = new Resizer {
|
||||||
|
def isTimeForResize(messageCounter: Long): Boolean = messageCounter == 0
|
||||||
|
def resize(routeeProvider: RouteeProvider): Unit = {
|
||||||
|
routeeProvider.createRoutees(nrOfInstances = 2)
|
||||||
|
latch.countDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val router = system.actorOf(Props[TestActor].withRouter(RoundRobinRouter(resizer = Some(resizer))))
|
||||||
|
watch(router)
|
||||||
|
Await.ready(latch, remaining)
|
||||||
|
router ! CurrentRoutees
|
||||||
|
val routees = expectMsgType[RouterRoutees].routees
|
||||||
|
routees.size must be(2)
|
||||||
|
routees foreach system.stop
|
||||||
|
// expect no Terminated
|
||||||
|
expectNoMsg(2.seconds)
|
||||||
|
}
|
||||||
|
|
||||||
"be able to send their routees" in {
|
"be able to send their routees" in {
|
||||||
case class TestRun(id: String, names: immutable.Iterable[String], actors: Int)
|
case class TestRun(id: String, names: immutable.Iterable[String], actors: Int)
|
||||||
val actor = system.actorOf(Props(new Actor {
|
val actor = system.actorOf(Props(new Actor {
|
||||||
|
|
|
||||||
|
|
@ -215,6 +215,12 @@ trait RouterConfig {
|
||||||
*/
|
*/
|
||||||
def verifyConfig(): Unit = ()
|
def verifyConfig(): Unit = ()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Specify that this router should stop itself when all routees have terminated (been removed).
|
||||||
|
* By Default it is `true`, unless a `resizer` is used.
|
||||||
|
*/
|
||||||
|
def stopRouterWhenAllRouteesRemoved: Boolean = resizer.isEmpty
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -373,7 +379,8 @@ trait Router extends Actor {
|
||||||
|
|
||||||
case Terminated(child) ⇒
|
case Terminated(child) ⇒
|
||||||
ref.removeRoutees(child :: Nil)
|
ref.removeRoutees(child :: Nil)
|
||||||
if (ref.routees.isEmpty) context.stop(self)
|
if (ref.routees.isEmpty && ref.routerConfig.stopRouterWhenAllRouteesRemoved)
|
||||||
|
context.stop(self)
|
||||||
|
|
||||||
}: Receive) orElse routerReceive
|
}: Receive) orElse routerReceive
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,8 @@ final case class ClusterRouterConfig(local: RouterConfig, settings: ClusterRoute
|
||||||
|
|
||||||
override def resizer: Option[Resizer] = local.resizer
|
override def resizer: Option[Resizer] = local.resizer
|
||||||
|
|
||||||
|
override def stopRouterWhenAllRouteesRemoved: Boolean = false
|
||||||
|
|
||||||
override def withFallback(other: RouterConfig): RouterConfig = other match {
|
override def withFallback(other: RouterConfig): RouterConfig = other match {
|
||||||
case ClusterRouterConfig(_: RemoteRouterConfig, _) ⇒ throw new IllegalStateException(
|
case ClusterRouterConfig(_: RemoteRouterConfig, _) ⇒ throw new IllegalStateException(
|
||||||
"ClusterRouterConfig is not allowed to wrap a RemoteRouterConfig")
|
"ClusterRouterConfig is not allowed to wrap a RemoteRouterConfig")
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,8 @@ direct children of their grand-parent instead.
|
||||||
|
|
||||||
If the child of a router terminates, the router will not automatically spawn
|
If the child of a router terminates, the router will not automatically spawn
|
||||||
a new child. In the event that all children of a router have terminated the
|
a new child. In the event that all children of a router have terminated the
|
||||||
router will terminate itself.
|
router will terminate itself, unless it is a dynamic router, e.g. using
|
||||||
|
a resizer.
|
||||||
|
|
||||||
Router usage
|
Router usage
|
||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
@ -378,7 +379,7 @@ documentation for details.
|
||||||
|
|
||||||
.. includecode:: code/docs/jrouting/RouterViaProgramDocTestBase.java#poisonPill
|
.. includecode:: code/docs/jrouting/RouterViaProgramDocTestBase.java#poisonPill
|
||||||
|
|
||||||
For a router, which normally passes on messages to routees, it is important to realised that
|
For a router, which normally passes on messages to routees, it is important to realise that
|
||||||
``PoisonPill`` messages are processed by the router only. ``PoisonPill`` messages sent to a router
|
``PoisonPill`` messages are processed by the router only. ``PoisonPill`` messages sent to a router
|
||||||
will *not* be sent on to routees.
|
will *not* be sent on to routees.
|
||||||
|
|
||||||
|
|
@ -399,7 +400,8 @@ routees aren't children of the router, i.e. even routees programmatically provid
|
||||||
With the code shown above, each routee will receive a ``PoisonPill`` message. Each routee will
|
With the code shown above, each routee will receive a ``PoisonPill`` message. Each routee will
|
||||||
continue to process its messages as normal, eventually processing the ``PoisonPill``. This will
|
continue to process its messages as normal, eventually processing the ``PoisonPill``. This will
|
||||||
cause the routee to stop. After all routees have stopped the router will itself be :ref:`stopped
|
cause the routee to stop. After all routees have stopped the router will itself be :ref:`stopped
|
||||||
automatically <note-router-terminated-children-java>`.
|
automatically <note-router-terminated-children-java>` unless it is a dynamic router, e.g. using
|
||||||
|
a resizer.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -151,7 +151,8 @@ direct children of their grand-parent instead.
|
||||||
|
|
||||||
If the child of a router terminates, the router will not automatically spawn
|
If the child of a router terminates, the router will not automatically spawn
|
||||||
a new child. In the event that all children of a router have terminated the
|
a new child. In the event that all children of a router have terminated the
|
||||||
router will terminate itself.
|
router will terminate itself unless it is a dynamic router, e.g. using
|
||||||
|
a resizer.
|
||||||
|
|
||||||
Router usage
|
Router usage
|
||||||
^^^^^^^^^^^^
|
^^^^^^^^^^^^
|
||||||
|
|
@ -396,7 +397,8 @@ routees aren't children of the router, i.e. even routees programmatically provid
|
||||||
With the code shown above, each routee will receive a ``PoisonPill`` message. Each routee will
|
With the code shown above, each routee will receive a ``PoisonPill`` message. Each routee will
|
||||||
continue to process its messages as normal, eventually processing the ``PoisonPill``. This will
|
continue to process its messages as normal, eventually processing the ``PoisonPill``. This will
|
||||||
cause the routee to stop. After all routees have stopped the router will itself be :ref:`stopped
|
cause the routee to stop. After all routees have stopped the router will itself be :ref:`stopped
|
||||||
automatically <note-router-terminated-children-scala>`.
|
automatically <note-router-terminated-children-scala>` unless it is a dynamic router, e.g. using
|
||||||
|
a resizer.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue