remove ActorContext.suspendForChildTermination, handle exceptions, add docs

This commit is contained in:
Roland 2012-03-01 17:36:05 +01:00
parent 4cea8ee83e
commit 37284bab4f
5 changed files with 31 additions and 55 deletions

View file

@ -142,17 +142,5 @@ class SupervisorMiscSpec extends AkkaSpec(SupervisorMiscSpec.config) with Defaul
expectMsg("green") 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")
}
} }
} }

View file

@ -134,14 +134,6 @@ trait ActorContext extends ActorRefFactory {
*/ */
def unwatch(subject: ActorRef): ActorRef 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 = final protected def writeObject(o: ObjectOutputStream): Unit =
throw new NotSerializableException("ActorContext is not serializable!") throw new NotSerializableException("ActorContext is not serializable!")
} }
@ -417,11 +409,6 @@ private[akka] class ActorCell(
subject subject
} }
final def suspendForChildTermination(): Unit = childrenRefs match {
case _: TerminatingChildrenContainer dispatcher suspend this
case _
}
final def children: Iterable[ActorRef] = childrenRefs.children 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)) 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 // prevent any further messages to be processed until the actor has been restarted
dispatcher.suspend(this) dispatcher.suspend(this)
actor.supervisorStrategy.handleSupervisorFailing(self, children)
} finally { } finally {
parent.tell(Failed(ActorInitializationException(self, "exception during re-creation", e)), self) 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)) 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 { childrenRefs match {
case tc @ TerminatingChildrenContainer(_, _, reason) case tc @ TerminatingChildrenContainer(_, _, reason)
val n = tc.remove(child) val n = tc.remove(child)
childrenRefs = n childrenRefs = n
actor.supervisorStrategy.handleChildTerminated(this, child, children) actor.supervisorStrategy.handleChildTerminated(this, child, children)
if (!n.isInstanceOf[TerminatingChildrenContainer]) reason match { if (!n.isInstanceOf[TerminatingChildrenContainer]) reason match {
case UserRequest if (mailbox.isSuspended) dispatcher resume this
case Recreation(cause) doRecreate(cause) case Recreation(cause) doRecreate(cause)
case Termination doTerminate() case Termination doTerminate()
case _
} }
case _ case _
childrenRefs = childrenRefs.remove(child) childrenRefs = childrenRefs.remove(child)
actor.supervisorStrategy.handleChildTerminated(this, child, children) 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 ⬅⬅⬅ // ➡➡➡ NEVER SEND THE SAME SYSTEM MESSAGE OBJECT TO TWO ACTORS ⬅⬅⬅

View file

@ -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 and therefore not receiving the stop command), this whole process will be
stuck. 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 Upon :meth:`ActorSystem.shutdown()`, the system guardian actors will be
stopped, and the aforementioned process will ensure proper termination of the stopped, and the aforementioned process will ensure proper termination of the
whole system. whole system.
@ -478,6 +467,13 @@ enables cleaning up of resources:
// close some file or database connection // 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 PoisonPill
---------- ----------

View file

@ -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 and therefore not receiving the stop command), this whole process will be
stuck. 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 Upon :meth:`ActorSystem.shutdown()`, the system guardian actors will be
stopped, and the aforementioned process will ensure proper termination of the stopped, and the aforementioned process will ensure proper termination of the
whole system. whole system.
@ -526,6 +515,13 @@ enables cleaning up of resources:
// close some file or database connection // 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 PoisonPill
---------- ----------