various documentation improvements

- document DeathWatch
- actorOf vs. actorFor
This commit is contained in:
Roland 2011-12-28 13:09:56 +01:00
parent a917260488
commit 2fbef5b5ce
7 changed files with 228 additions and 22 deletions

View file

@ -3,6 +3,10 @@
Actor References, Paths and Addresses
=====================================
.. sidebar:: Contents
.. contents:: :local:
This chapter describes how actors are identified and located within a possibly
distributed actor system. It ties into the central idea that
:ref:`actor-systems` form intrinsic supervision hierarchies as well as that
@ -225,6 +229,23 @@ extracting the sender references, and then watch all discovered concrete
actors. This scheme of resolving a selection may be improved upon in a future
release.
.. _actorOf-vs-actorFor:
Summary: ``actorOf`` vs. ``actorFor``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. note::
What the above sections described in some detail can be summarized and
memorized easily as follows:
- ``actorOf`` only ever creates a new actor, and it creates it as a direct
child of the context on which this method is invoked (which may be any
actor or actor system).
- ``actorFor`` only ever looks up an existing actor, i.e. does not create
one.
The Interplay with Remote Deployment
------------------------------------

View file

@ -24,6 +24,10 @@ import static akka.actor.Actors.*;
import akka.japi.Procedure;
//#import-procedure
//#import-watch
import akka.actor.Terminated;
//#import-watch
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.actor.UntypedActorFactory;
@ -161,6 +165,15 @@ public class UntypedActorDocTestBase {
system.shutdown();
}
@Test
public void useWatch() {
ActorSystem system = ActorSystem.create("MySystem");
ActorRef myActor = system.actorOf(new Props(WatchActor.class));
Future<Object> future = myActor.ask("kill", 1000);
assert Await.result(future, Duration.parse("1 second")).equals("finished");
system.shutdown();
}
public static class MyActor extends UntypedActor {
public MyActor(String s) {
@ -251,4 +264,27 @@ public class UntypedActorDocTestBase {
}
//#hot-swap-actor
//#watch
public static class WatchActor extends UntypedActor {
final ActorRef child = this.getContext().actorOf(Props.empty(), "child");
{
this.getContext().watch(child); // <-- this is the only call needed for registration
}
ActorRef lastSender = getContext().system().deadLetters();
@Override
public void onReceive(Object message) {
if (message.equals("kill")) {
getContext().stop(child);
lastSender = getSender();
} else if (message instanceof Terminated) {
final Terminated t = (Terminated) message;
if (t.getActor() == child) {
lastSender.tell("finished");
}
}
}
}
//#watch
}

View file

@ -28,6 +28,10 @@ its syntax from Erlang.
Creating Actors
===============
Since Akka enforces parental supervision every actor is supervised and
(potentially) the supervisor of its children; it is advisable that you
familiarize yourself with :ref:`actor-systems` and :ref:`supervision` and it
may also help to read :ref:`actorOf-vs-actorFor`.
Defining an Actor class
-----------------------
@ -131,6 +135,7 @@ In addition, it offers:
* system that the actor belongs to
* parent supervisor
* supervised children
* lifecycle monitoring
* hotswap behavior stack as described in :ref:`UntypedActor.HotSwap`
The remaining visible methods are user-overridable life-cycle hooks which are
@ -141,6 +146,36 @@ described in the following:
The implementations shown above are the defaults provided by the :class:`UntypedActor`
class.
.. _deathwatch-java:
Lifecycle Monitoring aka DeathWatch
-----------------------------------
In order to be notified when another actor terminates (i.e. stops permanently,
not temporary failure and restart), an actor may register itself for reception
of the :class:`Terminated` message dispatched by the other actor upon
termination (see `Stopping Actors`_). This service is provided by the
:class:`DeathWatch` component of the actor system.
Registering a monitor is easy (see fourth line, the rest is for demonstrating
the whole functionality):
.. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java#watch
It should be noted that the :class:`Terminated` message is generated
independent of the order in which registration and termination occur.
Registering multiple times does not necessarily lead to multiple messages being
generated, but there is no guarantee that only exactly one such message is
received: if termination of the watched actor has generated and queued the
message, and another registration is done before this message has been
processed, then a second message will be queued, because registering for
monitoring of an already terminated actor leads to the immediate generation of
the :class:`Terminated` message.
It is also possible to deregister from watching another actors liveliness
using ``context.unwatch(target)``, but obviously this cannot guarantee
non-reception of the :class:`Terminated` message because that may already have
been queued.
Start Hook
----------
@ -398,21 +433,44 @@ but additional messages in the mailbox will not be processed. By default these
messages are sent to the :obj:`deadLetters` of the :obj:`ActorSystem`, but that
depends on the mailbox implementation.
When stop is called then a call to the ``def postStop`` callback method will
take place. The ``Actor`` can use this callback to implement shutdown behavior.
Termination of an actor proceeds in two steps: first the actor suspends its
mailbox processing and sends a stop command to all its children, then it keeps
processing the termination messages from its children until the last one is
gone, finally terminating itself (invoking :meth:`postStop`, dumping mailbox,
publishing :class:`Terminated` on the :ref:`DeathWatch <deathwatch-java>`, telling
its supervisor). This procedure ensures that actor system sub-trees terminate
in an orderly fashion, propagating the stop command to the leaves and
collecting their confirmation back to the stopped supervisor. If one of the
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.
The :meth:`postStop()` hook is invoked after an actor is fully stopped. This
enables cleaning up of resources:
.. code-block:: java
@Override
public void postStop() {
... // clean up resources
// close some file or database connection
}
All Actors are stopped when the ``ActorSystem`` is stopped.
Supervised actors are stopped when the supervisor is stopped, i.e. children are stopped
when parent is stopped.
PoisonPill
----------
@ -421,9 +479,6 @@ stop the actor when the message is processed. ``PoisonPill`` is enqueued as
ordinary messages and will be handled after messages that were already queued
in the mailbox.
If the ``PoisonPill`` was sent with ``ask``, the ``Future`` will be completed with an
``akka.actor.ActorKilledException("PoisonPill")``.
Use it like this:
.. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java

View file

@ -12,3 +12,18 @@ changes in client code. This API cleanup is planned to be the last one for a
significant amount of time.
Detailed migration guide will be written.
Unordered Collection of Migration Items
=======================================
``ActorRef.ask()``
------------------
The mechanism for collecting an actors reply in a :class:`Future` has been
reworked for better location transparency: it uses an actor under the hood.
This actor needs to be disposable by the garbage collector in case no reply is
ever received, and the decision is based upon a timeout. This timeout
determines when the actor will stop itself and hence closes the window for a
reply to be received; it is independent of the timeout applied when awaiting
completion of the :class:`Future`, however, the actor will complete the
:class:`Future` with an :class:`AskTimeoutException` when it stops itself.

View file

@ -28,6 +28,10 @@ its syntax from Erlang.
Creating Actors
===============
Since Akka enforces parental supervision every actor is supervised and
(potentially) the supervisor of its children; it is advisable that you
familiarize yourself with :ref:`actor-systems` and :ref:`supervision` and it
may also help to read :ref:`actorOf-vs-actorFor`.
Defining an Actor class
-----------------------
@ -156,6 +160,7 @@ In addition, it offers:
* system that the actor belongs to
* parent supervisor
* supervised children
* lifecycle monitoring
* hotswap behavior stack as described in :ref:`Actor.HotSwap`
You can import the members in the :obj:`context` to avoid prefixing access with ``context.``
@ -176,6 +181,35 @@ described in the following::
The implementations shown above are the defaults provided by the :class:`Actor`
trait.
.. _deathwatch-scala:
Lifecycle Monitoring aka DeathWatch
-----------------------------------
In order to be notified when another actor terminates (i.e. stops permanently,
not temporary failure and restart), an actor may register itself for reception
of the :class:`Terminated` message dispatched by the other actor upon
termination (see `Stopping Actors`_). This service is provided by the
:class:`DeathWatch` component of the actor system.
Registering a monitor is easy:
.. includecode:: code/akka/docs/actor/ActorDocSpec.scala#watch
It should be noted that the :class:`Terminated` message is generated
independent of the order in which registration and termination occur.
Registering multiple times does not necessarily lead to multiple messages being
generated, but there is no guarantee that only exactly one such message is
received: if termination of the watched actor has generated and queued the
message, and another registration is done before this message has been
processed, then a second message will be queued, because registering for
monitoring of an already terminated actor leads to the immediate generation of
the :class:`Terminated` message.
It is also possible to deregister from watching another actors liveliness
using ``context.unwatch(target)``, but obviously this cannot guarantee
non-reception of the :class:`Terminated` message because that may already have
been queued.
Start Hook
----------
@ -457,19 +491,42 @@ but additional messages in the mailbox will not be processed. By default these
messages are sent to the :obj:`deadLetters` of the :obj:`ActorSystem`, but that
depends on the mailbox implementation.
When stop is called then a call to the ``def postStop`` callback method will
take place. The ``Actor`` can use this callback to implement shutdown behavior.
Termination of an actor proceeds in two steps: first the actor suspends its
mailbox processing and sends a stop command to all its children, then it keeps
processing the termination messages from its children until the last one is
gone, finally terminating itself (invoking :meth:`postStop`, dumping mailbox,
publishing :class:`Terminated` on the :ref:`DeathWatch <deathwatch-scala>`, telling
its supervisor). This procedure ensures that actor system sub-trees terminate
in an orderly fashion, propagating the stop command to the leaves and
collecting their confirmation back to the stopped supervisor. If one of the
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.
The :meth:`postStop()` hook is invoked after an actor is fully stopped. This
enables cleaning up of resources:
.. code-block:: scala
override def postStop() = {
... // clean up resources
// close some file or database connection
}
All Actors are stopped when the ``ActorSystem`` is stopped.
Supervised actors are stopped when the supervisor is stopped, i.e. children are stopped
when parent is stopped.
PoisonPill
----------
@ -479,10 +536,6 @@ stop the actor when the message is processed. ``PoisonPill`` is enqueued as
ordinary messages and will be handled after messages that were already queued
in the mailbox.
If the ``PoisonPill`` was sent with ``?``, the ``Future`` will be completed with an
``akka.actor.ActorKilledException("PoisonPill")``.
.. _Actor.HotSwap:
Become/Unbecome

View file

@ -296,4 +296,25 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
val actor = system.actorOf(Props(new HotSwapActor), name = "hot")
}
"using watch" in {
//#watch
import akka.actor.{ Actor, Props, Terminated }
class WatchActor extends Actor {
val child = context.actorOf(Props.empty, "child")
context.watch(child) // <-- this is the only call needed for registration
var lastSender = system.deadLetters
def receive = {
case "kill" context.stop(child); lastSender = sender
case Terminated(`child`) lastSender ! "finished"
}
}
//#watch
val a = system.actorOf(Props(new WatchActor))
implicit val sender = testActor
a ! "kill"
expectMsg("finished")
}
}

View file

@ -125,6 +125,11 @@ This enables the remoting by installing the :class:`RemoteActorRefProvider` and
chooses the default remote transport. All other options will be set
specifically for each show case.
.. note::
Be sure to replace the default IP 127.0.0.1 with the real address the system
is reachable by if you deploy onto multiple machines!
.. _remote-lookup-sample:
Remote Lookup