diff --git a/akka-actor-tests/src/test/scala/akka/actor/SupervisorMiscSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/SupervisorMiscSpec.scala index 43a5b97990..92af540a9a 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/SupervisorMiscSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/SupervisorMiscSpec.scala @@ -142,17 +142,5 @@ class SupervisorMiscSpec extends AkkaSpec(SupervisorMiscSpec.config) with Defaul expectMsg("green") } - "support suspending until all dying children have properly expired" in { - val parent = system.actorOf(Props(new Actor { - val child = context.actorOf(Props.empty, "bob") - def receive = { - case "engage" ⇒ context.stop(child); context.suspendForChildTermination(); self ! "next" - case "next" ⇒ context.actorOf(Props.empty, "bob"); testActor ! "green" - } - })) - parent ! "engage" - expectMsg("green") - } - } } diff --git a/akka-actor/src/main/scala/akka/actor/ActorCell.scala b/akka-actor/src/main/scala/akka/actor/ActorCell.scala index 7c899df7cd..e0423d075c 100644 --- a/akka-actor/src/main/scala/akka/actor/ActorCell.scala +++ b/akka-actor/src/main/scala/akka/actor/ActorCell.scala @@ -134,14 +134,6 @@ trait ActorContext extends ActorRefFactory { */ def unwatch(subject: ActorRef): ActorRef - /** - * Suspend this actor (after finishing processing of the current message) - * until all children for which stop(child) has been called have actually - * terminated. This is useful if a new child with the same name needs to - * be created before processing can continue. - */ - def suspendForChildTermination(): Unit - final protected def writeObject(o: ObjectOutputStream): Unit = throw new NotSerializableException("ActorContext is not serializable!") } @@ -417,11 +409,6 @@ private[akka] class ActorCell( subject } - final def suspendForChildTermination(): Unit = childrenRefs match { - case _: TerminatingChildrenContainer ⇒ dispatcher suspend this - case _ ⇒ - } - final def children: Iterable[ActorRef] = childrenRefs.children /** @@ -686,6 +673,7 @@ private[akka] class ActorCell( dispatcher.reportFailure(new LogEventException(Error(e, self.path.toString, clazz(actor), "error while creating actor"), e)) // prevent any further messages to be processed until the actor has been restarted dispatcher.suspend(this) + actor.supervisorStrategy.handleSupervisorFailing(self, children) } finally { parent.tell(Failed(ActorInitializationException(self, "exception during re-creation", e)), self) } @@ -696,21 +684,29 @@ private[akka] class ActorCell( case None ⇒ system.eventStream.publish(Warning(self.path.toString, clazz(actor), "dropping Failed(" + cause + ") from unknown child " + child)) } - final def handleChildTerminated(child: ActorRef): Unit = { + final def handleChildTerminated(child: ActorRef): Unit = try { childrenRefs match { case tc @ TerminatingChildrenContainer(_, _, reason) ⇒ val n = tc.remove(child) childrenRefs = n actor.supervisorStrategy.handleChildTerminated(this, child, children) if (!n.isInstanceOf[TerminatingChildrenContainer]) reason match { - case UserRequest ⇒ if (mailbox.isSuspended) dispatcher resume this case Recreation(cause) ⇒ doRecreate(cause) case Termination ⇒ doTerminate() + case _ ⇒ } case _ ⇒ childrenRefs = childrenRefs.remove(child) actor.supervisorStrategy.handleChildTerminated(this, child, children) } + } catch { + case NonFatal(e) ⇒ + try { + dispatcher suspend this + actor.supervisorStrategy.handleSupervisorFailing(self, children) + } finally { + parent.tell(Failed(e), self) + } } // ➡➡➡ NEVER SEND THE SAME SYSTEM MESSAGE OBJECT TO TWO ACTORS ⬅⬅⬅ diff --git a/akka-docs/java/typed-actors.rst b/akka-docs/java/typed-actors.rst index 0a78a122a1..6f59fc4ebb 100644 --- a/akka-docs/java/typed-actors.rst +++ b/akka-docs/java/typed-actors.rst @@ -179,10 +179,10 @@ By having your Typed Actor implementation class implement any and all of the fol * ``TypedActor.PreRestart`` * ``TypedActor.PostRestart`` - You can hook into the lifecycle of your Typed Actor. +You can hook into the lifecycle of your Typed Actor. - Proxying - -------- +Proxying +-------- - You can use the ``typedActorOf`` that takes a TypedProps and an ActorRef to proxy the given ActorRef as a TypedActor. - This is usable if you want to communicate remotely with TypedActors on other machines, just look them up with ``actorFor`` and pass the ``ActorRef`` to ``typedActorOf``. +You can use the ``typedActorOf`` that takes a TypedProps and an ActorRef to proxy the given ActorRef as a TypedActor. +This is usable if you want to communicate remotely with TypedActors on other machines, just look them up with ``actorFor`` and pass the ``ActorRef`` to ``typedActorOf``. diff --git a/akka-docs/java/untyped-actors.rst b/akka-docs/java/untyped-actors.rst index 5120bb908d..b898cb7dbe 100644 --- a/akka-docs/java/untyped-actors.rst +++ b/akka-docs/java/untyped-actors.rst @@ -453,17 +453,6 @@ actors does not respond (i.e. processing a message for extended periods of time and therefore not receiving the stop command), this whole process will be stuck. -It is possible to disregard specific children with respect to shutdown -confirmation by stopping them explicitly before issuing the -``context.stop(self)``:: - - context.stop(someChild); - context.stop(self); - -In this case ``someChild`` will be stopped asynchronously and re-parented to -the :class:`Locker`, where :class:`DavyJones` will keep tabs and dispose of it -eventually. - Upon :meth:`ActorSystem.shutdown()`, the system guardian actors will be stopped, and the aforementioned process will ensure proper termination of the whole system. @@ -478,6 +467,13 @@ enables cleaning up of resources: // close some file or database connection } +.. note:: + + Since stopping an actor is asynchronous, you cannot immediately reuse the + name of the child you just stopped; this will result in an + :class:`InvalidActorNameException`. Instead, :meth:`watch()` the terminating + actor and create its replacement in response to the :class:`Terminated` + message which will eventually arrive. PoisonPill ---------- diff --git a/akka-docs/scala/actors.rst b/akka-docs/scala/actors.rst index 01ef6ade83..b7ff85c31f 100644 --- a/akka-docs/scala/actors.rst +++ b/akka-docs/scala/actors.rst @@ -502,17 +502,6 @@ actors does not respond (i.e. processing a message for extended periods of time and therefore not receiving the stop command), this whole process will be stuck. -It is possible to disregard specific children with respect to shutdown -confirmation by stopping them explicitly before issuing the -``context.stop(self)``:: - - context.stop(someChild) - context.stop(self) - -In this case ``someChild`` will be stopped asynchronously and re-parented to -the :class:`Locker`, where :class:`DavyJones` will keep tabs and dispose of it -eventually. - Upon :meth:`ActorSystem.shutdown()`, the system guardian actors will be stopped, and the aforementioned process will ensure proper termination of the whole system. @@ -526,6 +515,13 @@ enables cleaning up of resources: // close some file or database connection } +.. note:: + + Since stopping an actor is asynchronous, you cannot immediately reuse the + name of the child you just stopped; this will result in an + :class:`InvalidActorNameException`. Instead, :meth:`watch()` the terminating + actor and create its replacement in response to the :class:`Terminated` + message which will eventually arrive. PoisonPill ---------- @@ -660,4 +656,4 @@ extend that, either through inheritance or delegation, is to use Or: -.. includecode:: code/akka/docs/actor/ActorDocSpec.scala#receive-orElse2 \ No newline at end of file +.. includecode:: code/akka/docs/actor/ActorDocSpec.scala#receive-orElse2