better document become semantics, see #2683
This commit is contained in:
parent
8eec825f18
commit
f9eb59e883
7 changed files with 54 additions and 57 deletions
|
|
@ -76,8 +76,14 @@ trait ActorContext extends ActorRefFactory {
|
|||
|
||||
/**
|
||||
* Changes the Actor's behavior to become the new 'Receive' (PartialFunction[Any, Unit]) handler.
|
||||
* Puts the behavior on top of the hotswap stack.
|
||||
* If "discardOld" is true, an unbecome will be issued prior to pushing the new behavior to the stack
|
||||
* This method acts upon the behavior stack as follows:
|
||||
*
|
||||
* - if `discardOld = true` it will replace the top element (i.e. the current behavior)
|
||||
* - if `discardOld = false` it will keep the current behavior and push the given one atop
|
||||
*
|
||||
* The default of replacing the current behavior has been chosen to avoid memory leaks in
|
||||
* case client code is written without consulting this documentation first (i.e. always pushing
|
||||
* new closures and never issuing an `unbecome()`)
|
||||
*/
|
||||
def become(behavior: Actor.Receive, discardOld: Boolean = true): Unit
|
||||
|
||||
|
|
@ -167,14 +173,20 @@ trait UntypedActorContext extends ActorContext {
|
|||
|
||||
/**
|
||||
* Changes the Actor's behavior to become the new 'Procedure' handler.
|
||||
* Puts the behavior on top of the hotswap stack.
|
||||
* Replaces the current behavior at the top of the hotswap stack.
|
||||
*/
|
||||
def become(behavior: Procedure[Any]): Unit
|
||||
|
||||
/**
|
||||
* Changes the Actor's behavior to become the new 'Procedure' handler.
|
||||
* Puts the behavior on top of the hotswap stack.
|
||||
* If "discardOld" is true, an unbecome will be issued prior to pushing the new behavior to the stack
|
||||
* This method acts upon the behavior stack as follows:
|
||||
*
|
||||
* - if `discardOld = true` it will replace the top element (i.e. the current behavior)
|
||||
* - if `discardOld = false` it will keep the current behavior and push the given one atop
|
||||
*
|
||||
* The default of replacing the current behavior has been chosen to avoid memory leaks in
|
||||
* case client code is written without consulting this documentation first (i.e. always pushing
|
||||
* new closures and never issuing an `unbecome()`)
|
||||
*/
|
||||
def become(behavior: Procedure[Any], discardOld: Boolean): Unit
|
||||
|
||||
|
|
|
|||
|
|
@ -16,13 +16,13 @@ import akka.AkkaException
|
|||
* def receive = {
|
||||
* case "open" ⇒
|
||||
* unstashAll()
|
||||
* context.become {
|
||||
* context.become({
|
||||
* case "write" ⇒ // do writing...
|
||||
* case "close" ⇒
|
||||
* unstashAll()
|
||||
* context.unbecome()
|
||||
* case msg ⇒ stash()
|
||||
* }
|
||||
* }, discardOld = false)
|
||||
* case "done" ⇒ // done
|
||||
* case msg ⇒ stash()
|
||||
* }
|
||||
|
|
|
|||
|
|
@ -32,9 +32,9 @@ public class UntypedActorSwapper {
|
|||
@Override
|
||||
public void apply(Object message) {
|
||||
log.info("Ho");
|
||||
getContext().unbecome(); // resets the latest 'become' (just for fun)
|
||||
getContext().unbecome(); // resets the latest 'become'
|
||||
}
|
||||
});
|
||||
}, false); // this signals stacking of the new behavior
|
||||
} else {
|
||||
unhandled(message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -549,7 +549,8 @@ Upgrade
|
|||
|
||||
Akka supports hotswapping the Actor’s message loop (e.g. its implementation) at
|
||||
runtime. Use the ``getContext().become`` method from within the Actor.
|
||||
The hotswapped code is kept in a Stack which can be pushed and popped.
|
||||
The hotswapped code is kept in a Stack which can be pushed (replacing or adding
|
||||
at the top) and popped.
|
||||
|
||||
.. warning::
|
||||
|
||||
|
|
@ -563,26 +564,20 @@ To hotswap the Actor using ``getContext().become``:
|
|||
.. includecode:: code/docs/actor/UntypedActorDocTestBase.java
|
||||
:include: hot-swap-actor
|
||||
|
||||
The ``become`` method is useful for many different things, such as to implement
|
||||
a Finite State Machine (FSM).
|
||||
This variant of the :meth:`become` method is useful for many different things,
|
||||
such as to implement a Finite State Machine (FSM). It will replace the current
|
||||
behavior (i.e. the top of the behavior stack), which means that
|
||||
:meth:`unbecome` is not called, instead always the next behavior is explicitly
|
||||
installed.
|
||||
|
||||
Here is another little cute example of ``become`` and ``unbecome`` in action:
|
||||
The other way of using :meth:`become` does not replace but add to the top of
|
||||
the behavior stack. In this case care must be taken to ensure that the number
|
||||
of “pop” operations (i.e. :meth:`unbecome`) matches the number of “push” ones
|
||||
in the long run, otherwise this amounts to a memory leak (which is why this
|
||||
behavior is not the default).
|
||||
|
||||
.. includecode:: code/docs/actor/UntypedActorSwapper.java#swapper
|
||||
|
||||
Downgrade
|
||||
---------
|
||||
|
||||
Since the hotswapped code is pushed to a Stack you can downgrade the code as
|
||||
well. Use the ``getContext().unbecome`` method from within the Actor.
|
||||
|
||||
.. code-block:: java
|
||||
|
||||
public void onReceive(Object message) {
|
||||
if (message.equals("revert")) getContext().unbecome();
|
||||
}
|
||||
|
||||
|
||||
Stash
|
||||
=====
|
||||
|
||||
|
|
|
|||
|
|
@ -653,11 +653,10 @@ Upgrade
|
|||
-------
|
||||
|
||||
Akka supports hotswapping the Actor’s message loop (e.g. its implementation) at
|
||||
runtime: Invoke the ``context.become`` method from within the Actor.
|
||||
|
||||
Become takes a ``PartialFunction[Any, Unit]`` that implements
|
||||
the new message handler. The hotswapped code is kept in a Stack which can be
|
||||
pushed and popped.
|
||||
runtime: invoke the ``context.become`` method from within the Actor.
|
||||
:meth:`become` takes a ``PartialFunction[Any, Unit]`` that implements the new
|
||||
message handler. The hotswapped code is kept in a Stack which can be pushed and
|
||||
popped.
|
||||
|
||||
.. warning::
|
||||
|
||||
|
|
@ -667,38 +666,26 @@ To hotswap the Actor behavior using ``become``:
|
|||
|
||||
.. includecode:: code/docs/actor/ActorDocSpec.scala#hot-swap-actor
|
||||
|
||||
The ``become`` method is useful for many different things, but a particular nice
|
||||
example of it is in example where it is used to implement a Finite State Machine
|
||||
(FSM): `Dining Hakkers`_.
|
||||
This variant of the :meth:`become` method is useful for many different things,
|
||||
such as to implement a Finite State Machine (FSM, for an example see `Dining
|
||||
Hakkers`_). It will replace the current behavior (i.e. the top of the behavior
|
||||
stack), which means that :meth:`unbecome` is not called, instead always the
|
||||
next behavior is explicitly installed.
|
||||
|
||||
.. _Dining Hakkers: @github@/akka-samples/akka-sample-fsm/src/main/scala/DiningHakkersOnBecome.scala
|
||||
|
||||
Here is another little cute example of ``become`` and ``unbecome`` in action:
|
||||
The other way of using :meth:`become` does not replace but add to the top of
|
||||
the behavior stack. In this case care must be taken to ensure that the number
|
||||
of “pop” operations (i.e. :meth:`unbecome`) matches the number of “push” ones
|
||||
in the long run, otherwise this amounts to a memory leak (which is why this
|
||||
behavior is not the default).
|
||||
|
||||
.. includecode:: code/docs/actor/ActorDocSpec.scala#swapper
|
||||
|
||||
Encoding Scala Actors nested receives without accidentally leaking memory
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
See this `Unnested receive example <https://github.com/akka/akka/blob/master/akka-docs/scala/code/docs/actor/UnnestedReceives.scala>`_.
|
||||
|
||||
|
||||
Downgrade
|
||||
---------
|
||||
|
||||
Since the hotswapped code is pushed to a Stack you can downgrade the code as
|
||||
well, all you need to do is to: Invoke the ``context.unbecome`` method from within the Actor.
|
||||
|
||||
This will pop the Stack and replace the Actor's implementation with the
|
||||
``PartialFunction[Any, Unit]`` that is at the top of the Stack.
|
||||
|
||||
Here's how you use the ``unbecome`` method:
|
||||
|
||||
.. code-block:: scala
|
||||
|
||||
def receive = {
|
||||
case "revert" => context.unbecome()
|
||||
}
|
||||
See this `Unnested receive example <@github@/akka-docs/scala/code/docs/actor/UnnestedReceives.scala>`_.
|
||||
|
||||
|
||||
Stash
|
||||
|
|
|
|||
|
|
@ -96,11 +96,11 @@ class Swapper extends Actor {
|
|||
def receive = {
|
||||
case Swap ⇒
|
||||
log.info("Hi")
|
||||
become {
|
||||
become({
|
||||
case Swap ⇒
|
||||
log.info("Ho")
|
||||
unbecome() // resets the latest 'become' (just for fun)
|
||||
}
|
||||
}, discardOld = false) // push on top instead of replace
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,10 @@ Essentially turning method invocations into asynchronous dispatch instead of syn
|
|||
Typed Actors consist of 2 "parts", a public interface and an implementation, and if you've done any work in "enterprise" Java, this will be very familiar to you. As with normal Actors you have an external API (the public interface instance) that will delegate methodcalls asynchronously to
|
||||
a private instance of the implementation.
|
||||
|
||||
The advantage of Typed Actors vs. Actors is that with TypedActors you have a static contract, and don't need to define your own messages, the downside is that it places some limitations on what you can do and what you can't, i.e. you can't use become/unbecome.
|
||||
The advantage of Typed Actors vs. Actors is that with TypedActors you have a
|
||||
static contract, and don't need to define your own messages, the downside is
|
||||
that it places some limitations on what you can do and what you can't, i.e. you
|
||||
cannot use :meth:`become`/:meth:`unbecome`.
|
||||
|
||||
Typed Actors are implemented using `JDK Proxies <http://docs.oracle.com/javase/6/docs/api/java/lang/reflect/Proxy.html>`_ which provide a pretty easy-worked API to intercept method calls.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue