diff --git a/akka-docs/general/addressing.rst b/akka-docs/general/addressing.rst index 135c3a5fb4..a9485fd1b2 100644 --- a/akka-docs/general/addressing.rst +++ b/akka-docs/general/addressing.rst @@ -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 ------------------------------------ diff --git a/akka-docs/java/code/akka/docs/actor/UntypedActorDocTestBase.java b/akka-docs/java/code/akka/docs/actor/UntypedActorDocTestBase.java index bdd359892f..16311ca57b 100644 --- a/akka-docs/java/code/akka/docs/actor/UntypedActorDocTestBase.java +++ b/akka-docs/java/code/akka/docs/actor/UntypedActorDocTestBase.java @@ -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 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 + } diff --git a/akka-docs/java/untyped-actors.rst b/akka-docs/java/untyped-actors.rst index fa27b10437..f60699b59c 100644 --- a/akka-docs/java/untyped-actors.rst +++ b/akka-docs/java/untyped-actors.rst @@ -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 actor’s 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 `, 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 diff --git a/akka-docs/project/migration-guide-1.3.x-2.0.x.rst b/akka-docs/project/migration-guide-1.3.x-2.0.x.rst index 3e815f11ea..af66da471c 100644 --- a/akka-docs/project/migration-guide-1.3.x-2.0.x.rst +++ b/akka-docs/project/migration-guide-1.3.x-2.0.x.rst @@ -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 actor’s 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. diff --git a/akka-docs/scala/actors.rst b/akka-docs/scala/actors.rst index 9cf166d226..524e536101 100644 --- a/akka-docs/scala/actors.rst +++ b/akka-docs/scala/actors.rst @@ -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 actor’s 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 `, 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 diff --git a/akka-docs/scala/code/akka/docs/actor/ActorDocSpec.scala b/akka-docs/scala/code/akka/docs/actor/ActorDocSpec.scala index 06d32609d5..38e4436389 100644 --- a/akka-docs/scala/code/akka/docs/actor/ActorDocSpec.scala +++ b/akka-docs/scala/code/akka/docs/actor/ActorDocSpec.scala @@ -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") + } } diff --git a/akka-docs/scala/remoting.rst b/akka-docs/scala/remoting.rst index f23491bcf1..4b2318c58d 100644 --- a/akka-docs/scala/remoting.rst +++ b/akka-docs/scala/remoting.rst @@ -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