diff --git a/akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala b/akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala index 863742fc35..520c0de6bf 100644 --- a/akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala +++ b/akka-actor-tests/src/test/scala/akka/actor/ActorDSLSpec.scala @@ -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 }) + //#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 diff --git a/akka-docs/rst/scala/actors.rst b/akka-docs/rst/scala/actors.rst index 88559939e6..914c899a77 100644 --- a/akka-docs/rst/scala/actors.rst +++ b/akka-docs/rst/scala/actors.rst @@ -153,6 +153,61 @@ 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 defined +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, you’ll +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, 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: + +.. 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: + +.. 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 =========