Merge pull request #742 from akka/wip-2411-describe-ActorDSL-∂π

Wip 2411 describe actor dsl ∂π
This commit is contained in:
Roland Kuhn 2012-09-25 03:24:48 -07:00
commit 3307b6ebce
15 changed files with 213 additions and 91 deletions

View file

@ -7,7 +7,9 @@ package akka.actor
import language.postfixOps
import akka.testkit.{ AkkaSpec, EventFilter }
//#import
import akka.actor.ActorDSL._
//#import
import akka.event.Logging.Warning
import scala.concurrent.{ Await, Future }
import scala.concurrent.util.duration._
@ -88,11 +90,13 @@ class ActorDSLSpec extends AkkaSpec {
"A lightweight creator" must {
"support creating regular actors" in {
//#simple-actor
val a = actor(new Act {
become {
case "hello" sender ! "hi"
}
})
//#simple-actor
implicit val i = inbox()
a ! "hello"
@ -100,10 +104,12 @@ class ActorDSLSpec extends AkkaSpec {
}
"support setup/teardown" in {
//#simple-start-stop
val a = actor(new Act {
whenStarting { testActor ! "started" }
whenStopping { testActor ! "stopped" }
})
//#simple-start-stop
system stop a
expectMsg("started")
@ -111,6 +117,7 @@ class ActorDSLSpec extends AkkaSpec {
}
"support restart" in {
//#failing-actor
val a = actor(new Act {
become {
case "die" throw new Exception
@ -118,6 +125,7 @@ class ActorDSLSpec extends AkkaSpec {
whenFailing { (cause, msg) testActor ! (cause, msg) }
whenRestarted { cause testActor ! cause }
})
//#failing-actor
EventFilter[Exception](occurrences = 1) intercept {
a ! "die"
@ -129,10 +137,12 @@ class ActorDSLSpec extends AkkaSpec {
"support superviseWith" in {
val a = actor(new Act {
val system = null // shadow the implicit system
//#supervise-with
superviseWith(OneForOneStrategy() {
case e: Exception if e.getMessage == "hello" SupervisorStrategy.Stop
case _: Exception SupervisorStrategy.Resume
case e: Exception if e.getMessage == "hello" Stop
case _: Exception Resume
})
//#supervise-with
val child = actor("child")(new Act {
whenFailing { (_, _) }
become {
@ -157,6 +167,8 @@ class ActorDSLSpec extends AkkaSpec {
"supported nested declaration" in {
val system = this.system
//#nested-actor
// here we pass in the ActorRefFactory explicitly as an example
val a = actor(system, "fred")(new Act {
val b = actor("barney")(new Act {
whenStarting { context.parent ! ("hello from " + self) }
@ -165,11 +177,13 @@ class ActorDSLSpec extends AkkaSpec {
case x testActor ! x
}
})
//#nested-actor
expectMsg("hello from Actor[akka://ActorDSLSpec/user/fred/barney]")
lastSender must be(a)
}
"support Stash" in {
//#act-with-stash
val a = actor(new ActWithStash {
become {
case 1 stash()
@ -179,6 +193,7 @@ class ActorDSLSpec extends AkkaSpec {
}
}
})
//#act-with-stash
a ! 1
a ! 2

View file

@ -54,6 +54,36 @@ trait Creators { this: ActorDSL.type ⇒
private[this] var postRestartFun: Throwable Unit = null
private[this] var strategy: SupervisorStrategy = null
/**
* @see [[akka.actor.OneForOneStrategy]]
*/
def OneForOneStrategy = akka.actor.OneForOneStrategy
/**
* @see [[akka.actor.AllForOneStrategy]]
*/
def AllForOneStrategy = akka.actor.AllForOneStrategy
/**
* @see [[akka.actor.SupervisorStrategy]]
*/
def Stop = SupervisorStrategy.Stop
/**
* @see [[akka.actor.SupervisorStrategy]]
*/
def Restart = SupervisorStrategy.Restart
/**
* @see [[akka.actor.SupervisorStrategy]]
*/
def Resume = SupervisorStrategy.Resume
/**
* @see [[akka.actor.SupervisorStrategy]]
*/
def Escalate = SupervisorStrategy.Escalate
/**
* Add the given behavior on top of the behavior stack for this actor. This
* stack is cleared upon restart. Use `unbecome()` to pop an element off

View file

@ -200,8 +200,9 @@ Restart Hooks
-------------
All actors are supervised, i.e. linked to another actor with a fault
handling strategy. Actors will be restarted in case an exception is thrown while
processing a message. This restart involves the hooks mentioned above:
handling strategy. Actors may be restarted in case an exception is thrown while
processing a message (see :ref:`supervision`). This restart involves the hooks
mentioned above:
1. The old actor is informed by calling :meth:`preRestart` with the exception
which caused the restart and the message which triggered that exception; the

View file

@ -153,6 +153,64 @@ When spawning actors for specific sub-tasks from within an actor, it may be conv
there is not yet a way to detect these illegal accesses at compile time.
See also: :ref:`jmm-shared-state`
The Actor DSL
-------------
Simple actors—for example one-off workers or even when trying things out in the
REPL—can be created more concisely using the :class:`Act` trait. The supporting
infrastructure is bundled in the following import:
.. includecode:: ../../../akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala#import
This import is assumed for all code samples throughout this section. To define
a simple actor, the following is sufficient:
.. includecode:: ../../../akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala#simple-actor
Here, :meth:`actor` takes the role of either ``system.actorOf`` or
``context.actorOf``, depending on which context it is called in: it takes an
implicit :class:`ActorRefFactory`, which within an actor is available in the
form of the ``implicit val context: ActorContext``. Outside of an actor, youll
have to either declare an implicit :class:`ActorSystem`, or you can give the
factory explicitly (see further below).
Life-cycle hooks are also exposed as DSL elements (see `Start Hook`_ and `Stop
Hook`_ below), where later invocations of the methods shown below will replace
the contents of the respective hooks:
.. includecode:: ../../../akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala#simple-start-stop
The above is enough if the logical life-cycle of the actor matches the restart
cycles (i.e. ``whenStopping`` is executed before a restart and ``whenStarting``
afterwards). If that is not desired, use the following two hooks (see `Restart
Hooks`_ below):
.. includecode:: ../../../akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala#failing-actor
It is also possible to create nested actors, i.e. grand-children, like this:
.. includecode:: ../../../akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala#nested-actor
.. note::
In some cases it will be necessary to explicitly pass the
:class:`ActorRefFactory` to the :meth:`actor()` method (you will notice when
the compiler tells you about ambiguous implicits).
The grand-child will be supervised by the child; the supervisor strategy for
this relationship can also be configured using a DSL element (supervision
directives are part of the :class:`Act` trait):
.. includecode:: ../../../akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala#supervise-with
Last but not least there is a little bit of convenience magic built-in, which
detects if the runtime class of the statically given actor subtype extends the
:class:`Stash` trait (this is a complicated way of saying that ``new Act with
Stash`` would not work because its runtime erased type is just an anonymous
subtype of ``Act``). If you want to use this magic, simply extend
:class:`ActWithStash`:
.. includecode:: ../../../akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala#act-with-stash
Actor API
=========
@ -246,8 +304,9 @@ Restart Hooks
-------------
All actors are supervised, i.e. linked to another actor with a fault
handling strategy. Actors will be restarted in case an exception is thrown while
processing a message. This restart involves the hooks mentioned above:
handling strategy. Actors may be restarted in case an exception is thrown while
processing a message (see :ref:`supervision`). This restart involves the hooks
mentioned above:
1. The old actor is informed by calling :meth:`preRestart` with the exception
which caused the restart and the message which triggered that exception; the

View file

@ -406,4 +406,12 @@ class ActorDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
lastSender must be === system.actorFor("/user")
}
"using ActorDSL outside of akka.actor package" in {
import akka.actor.ActorDSL._
actor(new Act {
superviseWith(OneForOneStrategy() { case _ Stop; Restart; Resume; Escalate })
superviseWith(AllForOneStrategy() { case _ Stop; Restart; Resume; Escalate })
})
}
}

View file

@ -15,7 +15,7 @@ Components
ByteString
^^^^^^^^^^
A primary goal of Akka's IO module is to only communicate between actors with immutable objects. When dealing with network IO on the jvm ``Array[Byte]`` and ``ByteBuffer`` are commonly used to represent collections of ``Byte``\s, but they are mutable. Scala's collection library also lacks a suitably efficient immutable collection for ``Byte``\s. Being able to safely and efficiently move ``Byte``\s around is very important for this IO module, so ``ByteString`` was developed.
A primary goal of Akka's IO support is to only communicate between actors with immutable objects. When dealing with network IO on the jvm ``Array[Byte]`` and ``ByteBuffer`` are commonly used to represent collections of ``Byte``\s, but they are mutable. Scala's collection library also lacks a suitably efficient immutable collection for ``Byte``\s. Being able to safely and efficiently move ``Byte``\s around is very important for this IO support, so ``ByteString`` was developed.
``ByteString`` is a `Rope-like <http://en.wikipedia.org/wiki/Rope_(computer_science)>`_ data structure that is immutable and efficient. When 2 ``ByteString``\s are concatenated together they are both stored within the resulting ``ByteString`` instead of copying both to a new ``Array``. Operations such as ``drop`` and ``take`` return ``ByteString``\s that still reference the original ``Array``, but just change the offset and length that is visible. Great care has also been taken to make sure that the internal ``Array`` cannot be modified. Whenever a potentially unsafe ``Array`` is used to create a new ``ByteString`` a defensive copy is created. If you require a ``ByteString`` that only blocks a much memory as necessary for it's content, use the ``compact`` method to get a ``CompactByteString`` instance. If the ``ByteString`` represented only a slice of the original array, this will result in copying all bytes in that slice.
@ -138,13 +138,13 @@ Receiving messages from the ``IOManager``:
IO.Iteratee
^^^^^^^^^^^
Included with Akka's IO module is a basic implementation of ``Iteratee``\s. ``Iteratee``\s are an effective way of handling a stream of data without needing to wait for all the data to arrive. This is especially useful when dealing with non blocking IO since we will usually receive data in chunks which may not include enough information to process, or it may contain much more data then we currently need.
Included with Akka's IO support is a basic implementation of ``Iteratee``\s. ``Iteratee``\s are an effective way of handling a stream of data without needing to wait for all the data to arrive. This is especially useful when dealing with non blocking IO since we will usually receive data in chunks which may not include enough information to process, or it may contain much more data then we currently need.
This ``Iteratee`` implementation is much more basic then what is usually found. There is only support for ``ByteString`` input, and enumerators aren't used. The reason for this limited implementation is to reduce the amount of explicit type signatures needed and to keep things simple. It is important to note that Akka's ``Iteratee``\s are completely optional, incoming data can be handled in any way, including other ``Iteratee`` libraries.
``Iteratee``\s work by processing the data that it is given and returning either the result (with any unused input) or a continuation if more input is needed. They are monadic, so methods like ``flatMap`` can be used to pass the result of an ``Iteratee`` to another.
The basic ``Iteratee``\s included in the IO module can all be found in the ScalaDoc under ``akka.actor.IO``, and some of them are covered in the example below.
The basic ``Iteratee``\s included in the IO support can all be found in the ScalaDoc under ``akka.actor.IO``, and some of them are covered in the example below.
Examples
--------

View file

@ -1,28 +0,0 @@
Camel
===
Requirements
------------
To build and run Camel you need [Simple Build Tool][sbt] (sbt).
Running
-------
First time, 'sbt update' to get dependencies, then use 'sbt run'.
Here is an example. First type 'sbt' to start SBT interactively, the run 'update' and 'run':
> cd $AKKA_HOME
> % sbt
> > project akka-sample-camel
> > run
> > Choose 1 or 2 depending on what sample you wish to run
Notice
------
[akka]: http://akka.io
[sbt]: http://code.google.com/p/simple-build-tool/

View file

@ -0,0 +1,15 @@
Camel Sample
============
This sample is meant to be used by studying the code; it does not perform any
astounding functions when running it. If you want to run it, check out the akka
sources on your local hard drive, follow the [instructions for setting up Akka
with SBT](http://doc.akka.io/docs/akka/current/intro/getting-started.html).
When you start SBT within the checked-out akka source directory, you can run
this sample by typing
akka-sample-camel/run
and then choose which of the demonstrations you would like to run.
You can read more in the [Akka docs](http://akka.io/docs).

View file

@ -0,0 +1,20 @@
Cluster Sample
==============
This sample is meant to be used by studying the code; it does not perform any
astounding functions when running it. If you want to run it, check out the akka
sources on your local hard drive, follow the [instructions for setting up Akka
with SBT](http://doc.akka.io/docs/akka/current/intro/getting-started.html).
When you start SBT within the checked-out akka source directory, you can run
this sample by typing
akka-sample-cluster-experimental/run-main sample.cluster.simple.SimpleClusterApp 2551
and then from another terminal start more cluster nodes like this:
akka-sample-cluster-experimental/run-main sample.cluster.simple.SimpleClusterApp
Then you can start and stop cluster nodes and observe the messages printed by
the remaining ones, demonstrating cluster membership changes.
You can read more in the [Akka docs](http://akka.io/docs).

View file

@ -1,28 +0,0 @@
FSM
===
Requirements
------------
To build and run FSM you need [Simple Build Tool][sbt] (sbt).
Running
-------
First time, 'sbt update' to get dependencies, then to run Ants use 'sbt run'.
Here is an example. First type 'sbt' to start SBT interactively, the run 'update' and 'run':
> cd $AKKA_HOME
> % sbt
> > project akka-sample-fsm
> > run
> > Choose 1 or 2 depending on what sample you wish to run
Notice
------
[akka]: http://akka.io
[sbt]: http://code.google.com/p/simple-build-tool/

View file

@ -0,0 +1,15 @@
FSM Sample
==========
This sample is meant to be used by studying the code; it does not perform any
astounding functions when running it. If you want to run it, check out the akka
sources on your local hard drive, follow the [instructions for setting up Akka
with SBT](http://doc.akka.io/docs/akka/current/intro/getting-started.html).
When you start SBT within the checked-out akka source directory, you can run
this sample by typing
akka-sample-fsm/run
and then choose one of the two ways (one using `context.become` and one using FSM).
You can read more in the [Akka docs](http://akka.io/docs).

View file

@ -0,0 +1,13 @@
Hello World Sample
==================
This sample is meant to be used by studying the code; it does not perform any
astounding functions when running it. If you want to run it, check out the akka
sources on your local hard drive, follow the [instructions for setting up Akka
with SBT](http://doc.akka.io/docs/akka/current/intro/getting-started.html).
When you start SBT within the checked-out akka source directory, you can run
this sample by typing
akka-sample-hello/run
You can read more in the [Akka docs](http://akka.io/docs).

View file

@ -1,26 +0,0 @@
HELLO
=====
Requirements
------------
To build and run FSM you need [Simple Build Tool][sbt] (sbt).
Running
-------
First time, 'sbt update' to get dependencies, then to run Ants use 'sbt run'.
Here is an example. First type 'sbt' to start SBT interactively, the run 'update' and 'run':
> cd $AKKA_HOME
> % sbt
> > project akka-sample-hello
> > run
Notice
------
[akka]: http://akka.io
[sbt]: http://code.google.com/p/simple-build-tool/

View file

@ -0,0 +1,13 @@
HELLO
=====
This sample is meant to be used by studying the code; it does not perform any
astounding functions when running it. If you want to run it, check out the akka
sources on your local hard drive, follow the [instructions for setting up Akka
with SBT](http://doc.akka.io/docs/akka/current/intro/getting-started.html).
When you start SBT within the checked-out akka source directory, you can run
this sample by typing
akka-sample-hello/run
You can read more in the [Akka docs](http://akka.io/docs).

View file

@ -0,0 +1,15 @@
Multi-Node Test Sample
======================
This sample is meant to be used by studying the code; it does not perform any
astounding functions when running it. If you want to run it, check out the akka
sources on your local hard drive, follow the [instructions for setting up Akka
with SBT](http://doc.akka.io/docs/akka/current/intro/getting-started.html).
When you start SBT within the checked-out akka source directory, you can run
this sample by typing
akka-sample-multi-node-experimental/multi-jvm:test-only sample.multinode.MultiNodeSampleSpec
(You might have to pass a system property containing `akka.test.tags.include=long-running`.)
You can read more in the [Akka docs](http://akka.io/docs).