Merge pull request #1186 from akka/wip-2509-sender-preRestart-∂π

clarify `sender` in preRestart, see #2509
This commit is contained in:
Roland Kuhn 2013-02-22 07:52:51 -08:00
commit fc180cde22
6 changed files with 109 additions and 34 deletions

View file

@ -142,5 +142,21 @@ class SupervisorMiscSpec extends AkkaSpec(SupervisorMiscSpec.config) with Defaul
} }
} }
"have access to the failing childs reference in supervisorStrategy" in {
val parent = system.actorOf(Props(new Actor {
override val supervisorStrategy = OneForOneStrategy() {
case _: Exception testActor ! sender; SupervisorStrategy.Stop
}
def receive = {
case "doit" context.actorOf(Props.empty, "child") ! Kill
}
}))
EventFilter[ActorKilledException](occurrences = 1) intercept {
parent ! "doit"
}
val p = expectMsgType[ActorRef].path
p.parent must be === parent.path
p.name must be === "child"
}
} }
} }

View file

@ -24,6 +24,13 @@ sample as it is easy to follow the log output to understand what is happening in
fault-tolerance-sample fault-tolerance-sample
.. note::
If the strategy is declared inside the supervising actor (as opposed to
as a static property or class) its decider has access to all internal state of
the actor in a thread-safe fashion, including obtaining a reference to the
currently failed child (available as the ``getSender()`` of the failure message).
Creating a Supervisor Strategy Creating a Supervisor Strategy
------------------------------ ------------------------------

View file

@ -136,8 +136,20 @@ to have them converted into actual Debug messages).
In addition, it offers: In addition, it offers:
* :obj:`getSelf()` reference to the :class:`ActorRef` of the actor * :obj:`getSelf()` reference to the :class:`ActorRef` of the actor
* :obj:`getSender()` reference sender Actor of the last received message, typically used as described in :ref:`UntypedActor.Reply` * :obj:`getSender()` reference sender Actor of the last received message, typically used as described in :ref:`UntypedActor.Reply`
* :obj:`supervisorStrategy()` user overridable definition the strategy to use for supervising child actors * :obj:`supervisorStrategy()` user overridable definition the strategy to use for supervising child actors
This strategy is typically declared inside the actor in order to have access
to the actors internal state within the decider function: since failure is
communicated as a message sent to the supervisor and processed like other
messages (albeit outside of the normal behavior), all values and variables
within the actor are available, as is the ``getSender()`` reference (which will
be the immediate child reporting the failure; if the original failure
occurred within a distant descendant it is still reported one level up at a
time).
* :obj:`getContext()` exposes contextual information for the actor and the current message, such as: * :obj:`getContext()` exposes contextual information for the actor and the current message, such as:
* factory methods to create child actors (:meth:`actorOf`) * factory methods to create child actors (:meth:`actorOf`)
@ -212,16 +224,21 @@ mentioned above:
which caused the restart and the message which triggered that exception; the 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 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 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, in turn by its supervisor, or if an actor is restarted due to a siblings
preparing hand-over to the fresh actor instance, etc. failure. If the message is available, then that messages sender is also
By default it stops all children and calls :meth:`postStop`. accessible in the usual way (i.e. by calling ``getSender()``).
This method is the best place for cleaning up, preparing hand-over to the
fresh actor instance, etc. By default it stops all children and calls
:meth:`postStop`.
2. The initial factory from the ``actorOf`` call is used 2. The initial factory from the ``actorOf`` call is used
to produce the fresh instance. to produce the fresh instance.
3. The new actors :meth:`postRestart` method is invoked with the exception 3. The new actors :meth:`postRestart` method is invoked with the exception
which caused the restart. By default the :meth:`preStart` which caused the restart. By default the :meth:`preStart`
is called, just as in the normal start-up case. is called, just as in the normal start-up case.
An actor restart replaces only the actual actor object; the contents of the An actor restart replaces only the actual actor object; the contents of the
mailbox is unaffected by the restart, so processing of messages will resume mailbox is unaffected by the restart, so processing of messages will resume
after the :meth:`postRestart` hook returns. The message after the :meth:`postRestart` hook returns. The message
@ -660,29 +677,29 @@ kind of exception is thrown, e.g. a database exception.
What happens to the Message What happens to the Message
--------------------------- ---------------------------
If an exception is thrown while a message is being processed (so taken of his If an exception is thrown while a message is being processed (i.e. taken out of
mailbox and handed over to the receive), then this message will be lost. It is its mailbox and handed over to the current behavior), then this message will be
important to understand that it is not put back on the mailbox. So if you want lost. It is important to understand that it is not put back on the mailbox. So
to retry processing of a message, you need to deal with it yourself by catching if you want to retry processing of a message, you need to deal with it yourself
the exception and retry your flow. Make sure that you put a bound on the number by catching the exception and retry your flow. Make sure that you put a bound
of retries since you don't want a system to livelock (so consuming a lot of cpu on the number of retries since you don't want a system to livelock (so
cycles without making progress). consuming a lot of cpu cycles without making progress). Another possibility
would be to have a look at the :ref:`PeekMailbox pattern <mailbox-acking>`.
What happens to the mailbox What happens to the mailbox
--------------------------- ---------------------------
If an exception is thrown while a message is being processed, nothing happens to If an exception is thrown while a message is being processed, nothing happens to
the mailbox. If the actor is restarted, the same mailbox will be there. So all the mailbox. If the actor is restarted, the same mailbox will be there. So all
messages on that mailbox, will be there as well. messages on that mailbox will be there as well.
What happens to the actor What happens to the actor
------------------------- -------------------------
If an exception is thrown, the actor instance is discarded and a new instance is If code within an actor throws an exception, that actor is suspended and the
created. This new instance will now be used in the actor references to this actor supervision process is started (see :ref:`supervision`). Depending on the
(so this is done invisible to the developer). Note that this means that current supervisors decision the actor is resumed (as if nothing happened), restarted
state of the failing actor instance is lost if you don't store and restore it in (wiping out its internal state and starting from scratch) or terminated.
``preRestart`` and ``postRestart`` callbacks.
Initialization patterns Initialization patterns
======================= =======================

View file

@ -240,8 +240,20 @@ actual Debug messages).
In addition, it offers: In addition, it offers:
* :obj:`self` reference to the :class:`ActorRef` of the actor * :obj:`self` reference to the :class:`ActorRef` of the actor
* :obj:`sender` reference sender Actor of the last received message, typically used as described in :ref:`Actor.Reply` * :obj:`sender` reference sender Actor of the last received message, typically used as described in :ref:`Actor.Reply`
* :obj:`supervisorStrategy` user overridable definition the strategy to use for supervising child actors * :obj:`supervisorStrategy` user overridable definition the strategy to use for supervising child actors
This strategy is typically declared inside the actor in order to have access
to the actors internal state within the decider function: since failure is
communicated as a message sent to the supervisor and processed like other
messages (albeit outside of the normal behavior), all values and variables
within the actor are available, as is the ``sender`` reference (which will
be the immediate child reporting the failure; if the original failure
occurred within a distant descendant it is still reported one level up at a
time).
* :obj:`context` exposes contextual information for the actor and the current message, such as: * :obj:`context` exposes contextual information for the actor and the current message, such as:
* factory methods to create child actors (:meth:`actorOf`) * factory methods to create child actors (:meth:`actorOf`)
@ -324,16 +336,21 @@ mentioned above:
which caused the restart and the message which triggered that exception; the 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 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 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, in turn by its supervisor, or if an actor is restarted due to a siblings
preparing hand-over to the fresh actor instance, etc. failure. If the message is available, then that messages sender is also
By default it stops all children and calls :meth:`postStop`. accessible in the usual way (i.e. by calling ``sender``).
This method is the best place for cleaning up, preparing hand-over to the
fresh actor instance, etc. By default it stops all children and calls
:meth:`postStop`.
2. The initial factory from the ``actorOf`` call is used 2. The initial factory from the ``actorOf`` call is used
to produce the fresh instance. to produce the fresh instance.
3. The new actors :meth:`postRestart` method is invoked with the exception 3. The new actors :meth:`postRestart` method is invoked with the exception
which caused the restart. By default the :meth:`preStart` which caused the restart. By default the :meth:`preStart`
is called, just as in the normal start-up case. is called, just as in the normal start-up case.
An actor restart replaces only the actual actor object; the contents of the An actor restart replaces only the actual actor object; the contents of the
mailbox is unaffected by the restart, so processing of messages will resume mailbox is unaffected by the restart, so processing of messages will resume
after the :meth:`postRestart` hook returns. The message after the :meth:`postRestart` hook returns. The message
@ -788,29 +805,29 @@ kind of exception is thrown, e.g. a database exception.
What happens to the Message What happens to the Message
--------------------------- ---------------------------
If an exception is thrown while a message is being processed (so taken of his If an exception is thrown while a message is being processed (i.e. taken out of
mailbox and handed over to the receive), then this message will be lost. It is its mailbox and handed over to the current behavior), then this message will be
important to understand that it is not put back on the mailbox. So if you want lost. It is important to understand that it is not put back on the mailbox. So
to retry processing of a message, you need to deal with it yourself by catching if you want to retry processing of a message, you need to deal with it yourself
the exception and retry your flow. Make sure that you put a bound on the number by catching the exception and retry your flow. Make sure that you put a bound
of retries since you don't want a system to livelock (so consuming a lot of cpu on the number of retries since you don't want a system to livelock (so
cycles without making progress). consuming a lot of cpu cycles without making progress). Another possibility
would be to have a look at the :ref:`PeekMailbox pattern <mailbox-acking>`.
What happens to the mailbox What happens to the mailbox
--------------------------- ---------------------------
If an exception is thrown while a message is being processed, nothing happens to If an exception is thrown while a message is being processed, nothing happens to
the mailbox. If the actor is restarted, the same mailbox will be there. So all the mailbox. If the actor is restarted, the same mailbox will be there. So all
messages on that mailbox, will be there as well. messages on that mailbox will be there as well.
What happens to the actor What happens to the actor
------------------------- -------------------------
If an exception is thrown, the actor instance is discarded and a new instance is If code within an actor throws an exception, that actor is suspended and the
created. This new instance will now be used in the actor references to this actor supervision process is started (see :ref:`supervision`). Depending on the
(so this is done invisible to the developer). Note that this means that current supervisors decision the actor is resumed (as if nothing happened), restarted
state of the failing actor instance is lost if you don't store and restore it in (wiping out its internal state and starting from scratch) or terminated.
``preRestart`` and ``postRestart`` callbacks.
Extending Actors using PartialFunction chaining Extending Actors using PartialFunction chaining

View file

@ -49,6 +49,13 @@ The match statement which forms the bulk of the body is of type ``Decider``,
which is a ``PartialFunction[Throwable, Directive]``. This which is a ``PartialFunction[Throwable, Directive]``. This
is the piece which maps child failure types to their corresponding directives. is the piece which maps child failure types to their corresponding directives.
.. note::
If the strategy is declared inside the supervising actor (as opposed to
within a companion object) its decider has access to all internal state of
the actor in a thread-safe fashion, including obtaining a reference to the
currently failed child (available as the ``sender`` of the failure message).
Default Supervisor Strategy Default Supervisor Strategy
^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -427,3 +427,14 @@ Architecture in-depth
For further details on the design and internal architecture see :ref:`io-layer`. For further details on the design and internal architecture see :ref:`io-layer`.
.. _spray.io: http://spray.io .. _spray.io: http://spray.io
Link to the old IO documentation
--------------------------------
.. This is only in here to avoid a warning about io-old not being part of any toctree.
.. toctree::
:maxdepth: 1
io-old