make currentMessage available in preRestart, test #957
- use Option[Any] since currentMessage may be unavailable (supervisor being restarted) - plus docs
This commit is contained in:
parent
10256991cb
commit
956d055d87
4 changed files with 58 additions and 16 deletions
|
|
@ -36,7 +36,6 @@ object ActorRestartSpec {
|
|||
case "get" ⇒ self reply xx
|
||||
}
|
||||
override def preStart { testActor ! (("preStart", gen)) }
|
||||
override def postStop { testActor ! (("postStop", gen)) }
|
||||
override def preRestart(cause: Throwable) { testActor ! (("preRestart", gen)) }
|
||||
override def postRestart(cause: Throwable) { testActor ! (("postRestart", gen)) }
|
||||
override def freshInstance() = {
|
||||
|
|
@ -71,13 +70,21 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo
|
|||
import ActorRestartSpec._
|
||||
|
||||
override def beforeEach { generation = 0 }
|
||||
override def afterEach { toStop foreach (_.stop()) }
|
||||
|
||||
private var toStop = List.empty[ActorRef]
|
||||
private def newActor(f: ⇒ Actor): ActorRef = {
|
||||
val ref = actorOf(f)
|
||||
toStop ::= ref
|
||||
ref.start()
|
||||
}
|
||||
|
||||
"An Actor restart" must {
|
||||
|
||||
"invoke preRestart, preStart, postRestart" in {
|
||||
val actor = actorOf(new Restarter(testActor)).start()
|
||||
val actor = newActor(new Restarter(testActor))
|
||||
expectMsg(1 second, ("preStart", 1))
|
||||
val supervisor = actorOf[Supervisor].start()
|
||||
val supervisor = newActor(new Supervisor)
|
||||
supervisor link actor
|
||||
actor ! Kill
|
||||
within(1 second) {
|
||||
|
|
@ -89,9 +96,9 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo
|
|||
}
|
||||
|
||||
"support creation of nested actors in freshInstance()" in {
|
||||
val actor = actorOf(new Restarter(testActor)).start()
|
||||
val actor = newActor(new Restarter(testActor))
|
||||
expectMsg(1 second, ("preStart", 1))
|
||||
val supervisor = actorOf[Supervisor].start()
|
||||
val supervisor = newActor(new Supervisor)
|
||||
supervisor link actor
|
||||
actor ! Nested
|
||||
actor ! Kill
|
||||
|
|
@ -108,9 +115,9 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo
|
|||
}
|
||||
|
||||
"use freshInstance() if available" in {
|
||||
val actor = actorOf(new Restarter(testActor)).start()
|
||||
val actor = newActor(new Restarter(testActor))
|
||||
expectMsg(1 second, ("preStart", 1))
|
||||
val supervisor = actorOf[Supervisor].start()
|
||||
val supervisor = newActor(new Supervisor)
|
||||
supervisor link actor
|
||||
actor ! 42
|
||||
actor ! Handover
|
||||
|
|
@ -126,9 +133,9 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo
|
|||
}
|
||||
|
||||
"fall back to default factory if freshInstance() fails" in {
|
||||
val actor = actorOf(new Restarter(testActor)).start()
|
||||
val actor = newActor(new Restarter(testActor))
|
||||
expectMsg(1 second, ("preStart", 1))
|
||||
val supervisor = actorOf[Supervisor].start()
|
||||
val supervisor = newActor(new Supervisor)
|
||||
supervisor link actor
|
||||
actor ! 42
|
||||
actor ! Fail
|
||||
|
|
@ -143,6 +150,22 @@ class ActorRestartSpec extends WordSpec with MustMatchers with TestKit with Befo
|
|||
expectMsg(1 second, 0)
|
||||
}
|
||||
|
||||
"call preRestart(cause, currentMessage) if defined" in {
|
||||
val actor = newActor(new Actor {
|
||||
def receive = { case _ ⇒ }
|
||||
override def preRestart(cause: Throwable, currentMessage: Option[Any]) {
|
||||
testActor ! (("preRestart", currentMessage))
|
||||
}
|
||||
})
|
||||
val supervisor = newActor(new Supervisor)
|
||||
supervisor link actor
|
||||
actor ! Kill
|
||||
within(1 second) {
|
||||
expectMsg(("preRestart", Some(Kill)))
|
||||
expectNoMsg
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -658,10 +658,21 @@ trait Actor {
|
|||
/**
|
||||
* User overridable callback.
|
||||
* <p/>
|
||||
* Is called on a crashed Actor right BEFORE it is restarted to allow clean up of resources before Actor is terminated.
|
||||
* Is called on a crashed Actor right BEFORE it is restarted to allow clean
|
||||
* up of resources before Actor is terminated. Override either the variant
|
||||
* with or without the currentMessage argument.
|
||||
*/
|
||||
def preRestart(reason: Throwable) {}
|
||||
|
||||
/**
|
||||
* User overridable callback.
|
||||
* <p/>
|
||||
* Is called on a crashed Actor right BEFORE it is restarted to allow clean
|
||||
* up of resources before Actor is terminated. Override either the variant
|
||||
* with or without the currentMessage argument.
|
||||
*/
|
||||
def preRestart(reason: Throwable, message: Option[Any]) { preRestart(reason) }
|
||||
|
||||
/**
|
||||
* User overridable callback.
|
||||
* <p/>
|
||||
|
|
|
|||
|
|
@ -766,7 +766,8 @@ class LocalActorRef private[akka] (
|
|||
def performRestart() {
|
||||
val failedActor = actorInstance.get
|
||||
if (Actor.debugLifecycle) EventHandler.debug(failedActor, "restarting")
|
||||
failedActor.preRestart(reason)
|
||||
val message = if (currentMessage ne null) Some(currentMessage.message) else None
|
||||
failedActor.preRestart(reason, message)
|
||||
val freshActor = newActor
|
||||
setActorSelfFields(failedActor, null) // Only null out the references if we could instantiate the new actor
|
||||
actorInstance.set(freshActor) // Assign it here so if preStart fails, we can null out the sef-refs next call
|
||||
|
|
|
|||
|
|
@ -99,11 +99,15 @@ The :class:`Actor` trait defines only one abstract method, the abovementioned
|
|||
:meth:`receive`. In addition, it offers two convenience methods
|
||||
:meth:`become`/:meth:`unbecome` for modifying the hotswap behavior stack as
|
||||
described in :ref:`Actor.HotSwap` and the :obj:`self` reference to this actor’s
|
||||
:class:`ActorRef` object. The remaining visible methods are user-overridable
|
||||
life-cycle hooks which are described in the following::
|
||||
:class:`ActorRef` object. If the current actor behavior does not match a
|
||||
received message, :meth:`unhandled` is called, which by default throws an
|
||||
:class:`UnhandledMessageException`.
|
||||
|
||||
The remaining visible methods are user-overridable life-cycle hooks which are
|
||||
described in the following::
|
||||
|
||||
def preStart() {}
|
||||
def preRestart(cause: Throwable) {}
|
||||
def preRestart(cause: Throwable, message: Option[Any]) {}
|
||||
def freshInstance(): Option[Actor] = None
|
||||
def postRestart(cause: Throwable) {}
|
||||
def postStop() {}
|
||||
|
|
@ -135,7 +139,10 @@ handling strategy, will be restarted in case an exception is thrown while
|
|||
processing a message. This restart involves four of the hooks mentioned above:
|
||||
|
||||
1. The old actor is informed by calling :meth:`preRestart` with the exception
|
||||
which caused the restart; this method is the best place for cleaning up,
|
||||
which caused the restart and the message which triggered that exception; the
|
||||
latter may be ``None`` if the restart was not caused by processing a
|
||||
message, e.g. when a supervisor does not trap the exception and is restarted
|
||||
in turn by its supervisor. This method is the best place for cleaning up,
|
||||
preparing hand-over to the fresh actor instance, etc.
|
||||
2. The old actor’s :meth:`freshInstance` factory method is invoked, which may
|
||||
optionally produce the new actor instance which will replace this actor. If
|
||||
|
|
@ -158,7 +165,7 @@ processing a message. This restart involves four of the hooks mentioned above:
|
|||
An actor restart replaces only the actual actor object; the contents of the
|
||||
mailbox and the hotswap stack are unaffected by the restart, so processing of
|
||||
messages will resume after the :meth:`postRestart` hook returns. Any message
|
||||
sent to an actor which is being restarted will be queued to its mailbox as
|
||||
sent to an actor while it is being restarted will be queued to its mailbox as
|
||||
usual.
|
||||
|
||||
Stop Hook
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue