Merge branch 'master' into wip-channels-∂π

This commit is contained in:
Roland 2013-01-31 20:26:01 +01:00
commit 1b331dc547
575 changed files with 8084 additions and 6947 deletions

View file

@ -19,10 +19,10 @@ immediately available for reading by any thread (using ``get`` or ``apply``)
without any messages.
Agents are reactive. The update actions of all Agents get interleaved amongst
threads in a thread pool. At any point in time, at most one ``send`` action for
threads in an ``ExecutionContext``. At any point in time, at most one ``send`` action for
each Agent is being executed. Actions dispatched to an agent from another thread
will occur in the order they were sent, potentially interleaved with actions
dispatched to the same agent from other sources.
dispatched to the same agent from other threads.
If an Agent is used within an enclosing transaction, then it will participate in
that transaction. Agents are integrated with Scala STM - any dispatches made in
@ -30,32 +30,33 @@ a transaction are held until that transaction commits, and are discarded if it
is retried or aborted.
Creating and stopping Agents
Creating Agents
============================
Agents are created by invoking ``Agent(value)`` passing in the Agent's initial
value:
value and providing an implicit ``ExecutionContext`` to be used for it, for these
examples we're going to use the default global one, but YMMV:
.. includecode:: code/docs/agent/AgentDocSpec.scala#create
Note that creating an Agent requires an implicit ``ActorSystem`` (for creating
the underlying actors). See :ref:`actor-systems` for more information about
actor systems. An ActorSystem can be in implicit scope when creating an Agent:
Reading an Agent's value
========================
.. includecode:: code/docs/agent/AgentDocSpec.scala#create-implicit-system
Agents can be dereferenced (you can get an Agent's value) by invoking the Agent
with parentheses like this:
Or the ActorSystem can be passed explicitly when creating an Agent:
.. includecode:: code/docs/agent/AgentDocSpec.scala#read-apply
.. includecode:: code/docs/agent/AgentDocSpec.scala#create-explicit-system
Or by using the get method:
An Agent will be running until you invoke ``close`` on it. Then it will be
eligible for garbage collection (unless you hold on to it in some way).
.. includecode:: code/docs/agent/AgentDocSpec.scala#read-get
.. includecode:: code/docs/agent/AgentDocSpec.scala#close
Reading an Agent's current value does not involve any message passing and
happens immediately. So while updates to an Agent are asynchronous, reading the
state of an Agent is synchronous.
Updating Agents
===============
Updating Agents (send & alter)
==============================
You update an Agent by sending a function that transforms the current value or
by sending just a new value. The Agent will apply the new value or function
@ -75,37 +76,22 @@ in order.
.. includecode:: code/docs/agent/AgentDocSpec.scala#send-off
All ``send`` methods also have a corresponding ``alter`` method that returns a ``Future``.
See :ref:`futures-scala` for more information on ``Futures``.
Reading an Agent's value
========================
Agents can be dereferenced (you can get an Agent's value) by invoking the Agent
with parentheses like this:
.. includecode:: code/docs/agent/AgentDocSpec.scala#read-apply
Or by using the get method:
.. includecode:: code/docs/agent/AgentDocSpec.scala#read-get
Reading an Agent's current value does not involve any message passing and
happens immediately. So while updates to an Agent are asynchronous, reading the
state of an Agent is synchronous.
.. includecode:: code/docs/agent/AgentDocSpec.scala#alter
.. includecode:: code/docs/agent/AgentDocSpec.scala#alter-off
Awaiting an Agent's value
=========================
It is also possible to read the value after all currently queued sends have
completed. You can do this with ``await``:
.. includecode:: code/docs/agent/AgentDocSpec.scala#read-await
You can also get a ``Future`` to this value, that will be completed after the
You can also get a ``Future`` to the Agents value, that will be completed after the
currently queued updates have completed:
.. includecode:: code/docs/agent/AgentDocSpec.scala#read-future
See :ref:`futures-scala` for more information on ``Futures``.
Transactional Agents
====================

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.actor

View file

@ -1,11 +1,13 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.actor
import language.postfixOps
import akka.testkit.{ AkkaSpec MyFavoriteTestFrameWorkPlusAkkaTestKit }
import akka.util.ByteString
//#test-code
import akka.actor.Props
import scala.collection.immutable
@ -129,8 +131,7 @@ class FSMDocSpec extends MyFavoriteTestFrameWorkPlusAkkaTestKit {
//#transform-syntax
when(SomeState)(transform {
case Event(bytes: Array[Byte], read) stay using (read + bytes.length)
case Event(bytes: List[Byte], read) stay using (read + bytes.size)
case Event(bytes: ByteString, read) stay using (read + bytes.length)
} using {
case s @ FSM.State(state, read, timeout, stopReason, replies) if read > 1000
goto(Processing)
@ -144,8 +145,7 @@ class FSMDocSpec extends MyFavoriteTestFrameWorkPlusAkkaTestKit {
}
when(SomeState)(transform {
case Event(bytes: Array[Byte], read) stay using (read + bytes.length)
case Event(bytes: List[Byte], read) stay using (read + bytes.size)
case Event(bytes: ByteString, read) stay using (read + bytes.length)
} using processingTrigger)
//#alt-transform-syntax
@ -211,7 +211,7 @@ class FSMDocSpec extends MyFavoriteTestFrameWorkPlusAkkaTestKit {
expectMsg(Batch(immutable.Seq(45)))
}
"batch not if uninitialized" in {
"not batch if uninitialized" in {
val buncher = system.actorOf(Props(new Buncher))
buncher ! Queue(42)
expectNoMsg

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.actor

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.actor

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.actor
@ -29,7 +29,7 @@ class SchedulerDocSpec extends AkkaSpec(Map("akka.loglevel" -> "INFO")) {
expectMsg(1 second, "foo")
//#schedule-one-off-thunk
//Schedules a function to be executed (send the current time) to the testActor after 50ms
//Schedules a function to be executed (send a message to the testActor) after 50ms
system.scheduler.scheduleOnce(50 milliseconds) {
testActor ! System.currentTimeMillis
}

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.actor

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.actor

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.agent
@ -7,127 +7,98 @@ import language.postfixOps
import akka.agent.Agent
import scala.concurrent.duration._
import akka.util.Timeout
import scala.concurrent.{ Await, ExecutionContext }
import akka.testkit._
import scala.concurrent.Future
class AgentDocSpec extends AkkaSpec {
"create and close" in {
"create" in {
//#create
import scala.concurrent.ExecutionContext.Implicits.global
import akka.agent.Agent
val agent = Agent(5)
//#create
//#close
agent.close()
//#close
}
"create with implicit system" in {
//#create-implicit-system
import akka.actor.ActorSystem
import akka.agent.Agent
"read value" in {
import scala.concurrent.ExecutionContext.Implicits.global
val agent = Agent(0)
implicit val system = ActorSystem("app")
{
//#read-apply
val result = agent()
//#read-apply
result must be === 0
}
{
//#read-get
val result = agent.get
//#read-get
result must be === 0
}
val agent = Agent(5)
//#create-implicit-system
agent.close()
system.shutdown()
}
"create with explicit system" in {
//#create-explicit-system
import akka.actor.ActorSystem
import akka.agent.Agent
val system = ActorSystem("app")
val agent = Agent(5)(system)
//#create-explicit-system
agent.close()
system.shutdown()
{
//#read-future
val future = agent.future
//#read-future
Await.result(future, 5 seconds) must be === 0
}
}
"send and sendOff" in {
val agent = Agent(0)
import system.dispatcher
val agent = Agent(0)(ExecutionContext.global)
//#send
// send a value
// send a value, enqueues this change
// of the value of the Agent
agent send 7
// send a function
// send a function, enqueues this change
// to the value of the Agent
agent send (_ + 1)
agent send (_ * 2)
//#send
def longRunningOrBlockingFunction = (i: Int) i * 1
def longRunningOrBlockingFunction = (i: Int) i * 1 // Just for the example code
def someExecutionContext() = scala.concurrent.ExecutionContext.Implicits.global // Just for the example code
//#send-off
// the ExecutionContext you want to run the function on
implicit val ec = someExecutionContext()
// sendOff a function
agent sendOff (longRunningOrBlockingFunction)
agent sendOff longRunningOrBlockingFunction
//#send-off
val result = agent.await(Timeout(5 seconds))
result must be === 16
Await.result(agent.future, 5 seconds) must be === 16
}
"read with apply" in {
val agent = Agent(0)
"alter and alterOff" in {
val agent = Agent(0)(ExecutionContext.global)
//#alter
// alter a value
val f1: Future[Int] = agent alter 7
//#read-apply
val result = agent()
//#read-apply
// alter a function
val f2: Future[Int] = agent alter (_ + 1)
val f3: Future[Int] = agent alter (_ * 2)
//#alter
result must be === 0
}
def longRunningOrBlockingFunction = (i: Int) i * 1 // Just for the example code
def someExecutionContext() = ExecutionContext.global // Just for the example code
"read with get" in {
val agent = Agent(0)
//#alter-off
// the ExecutionContext you want to run the function on
implicit val ec = someExecutionContext()
// alterOff a function
val f4: Future[Int] = agent alterOff longRunningOrBlockingFunction
//#alter-off
//#read-get
val result = agent.get
//#read-get
result must be === 0
}
"read with await" in {
val agent = Agent(0)
//#read-await
import scala.concurrent.duration._
import akka.util.Timeout
implicit val timeout = Timeout(5 seconds)
val result = agent.await
//#read-await
result must be === 0
}
"read with future" in {
val agent = Agent(0)
//#read-future
import scala.concurrent.Await
implicit val timeout = Timeout(5 seconds)
val future = agent.future
val result = Await.result(future, timeout.duration)
//#read-future
result must be === 0
Await.result(f4, 5 seconds) must be === 16
}
"transfer example" in {
//#transfer-example
import scala.concurrent.ExecutionContext.Implicits.global
import akka.agent.Agent
import scala.concurrent.duration._
import akka.util.Timeout
import scala.concurrent.stm._
def transfer(from: Agent[Int], to: Agent[Int], amount: Int): Boolean = {
@ -145,25 +116,25 @@ class AgentDocSpec extends AkkaSpec {
val to = Agent(20)
val ok = transfer(from, to, 50)
implicit val timeout = Timeout(5 seconds)
val fromValue = from.await // -> 50
val toValue = to.await // -> 70
val fromValue = from.future // -> 50
val toValue = to.future // -> 70
//#transfer-example
fromValue must be === 50
toValue must be === 70
Await.result(fromValue, 5 seconds) must be === 50
Await.result(toValue, 5 seconds) must be === 70
ok must be === true
}
"monadic example" in {
def println(a: Any) = ()
//#monadic-example
import scala.concurrent.ExecutionContext.Implicits.global
val agent1 = Agent(3)
val agent2 = Agent(5)
// uses foreach
var result = 0
for (value agent1) {
result = value + 1
}
for (value agent1)
println(value)
// uses map
val agent3 = for (value agent1) yield value + 1
@ -178,15 +149,8 @@ class AgentDocSpec extends AkkaSpec {
} yield value1 + value2
//#monadic-example
result must be === 4
agent3() must be === 4
agent4() must be === 4
agent5() must be === 8
agent1.close()
agent2.close()
agent3.close()
agent4.close()
agent5.close()
}
}

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.camel
@ -70,4 +70,4 @@ object Consumers {
}
//#Consumer4
}
}
}

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.camel

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.dataflow

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.dispatcher

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.event

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.extension

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.extension

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.future

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.io

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.io

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.pattern

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.pattern

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.remoting
@ -20,15 +20,15 @@ object RemoteDeploymentDocSpec {
class RemoteDeploymentDocSpec extends AkkaSpec("""
akka.actor.provider = "akka.remote.RemoteActorRefProvider"
akka.remoting.transports.tcp.port = 0
akka.remote.netty.tcp.port = 0
""") with ImplicitSender {
import RemoteDeploymentDocSpec._
val other = ActorSystem("remote", system.settings.config)
val address = other.asInstanceOf[ExtendedActorSystem].provider.getExternalAddressFor(Address("tcp.akka", "s", "host", 1)).get
val address = other.asInstanceOf[ExtendedActorSystem].provider.getExternalAddressFor(Address("akka.tcp", "s", "host", 1)).get
override def atTermination() { other.shutdown() }
override def afterTermination() { other.shutdown() }
"demonstrate programmatic deployment" in {
//#deploy
@ -42,8 +42,8 @@ class RemoteDeploymentDocSpec extends AkkaSpec("""
"demonstrate address extractor" in {
//#make-address
val one = AddressFromURIString("tcp.akka://sys@host:1234")
val two = Address("tcp.akka", "sys", "host", 1234) // this gives the same
val one = AddressFromURIString("akka.tcp://sys@host:1234")
val two = Address("akka.tcp", "sys", "host", 1234) // this gives the same
//#make-address
one must be === two
}
@ -56,4 +56,4 @@ class RemoteDeploymentDocSpec extends AkkaSpec("""
//#sample-actor
}
}
}

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.routing

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.routing

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.routing
@ -91,4 +91,4 @@ class ParentActor extends Actor {
}
}
//#parentActor
//#parentActor

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.routing
@ -155,4 +155,4 @@ class RouterWithConfigDocSpec extends AkkaSpec(RouterWithConfigDocSpec.config) w
receiveN(10)
}
}
}

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.routing
@ -49,4 +49,4 @@ object RouterWithConfigExample extends App {
"router2")
//#configurableRoutingWithResizer
1 to 10 foreach { i router2 ! Message(i) }
}
}

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.routing
@ -50,4 +50,4 @@ object RoutingProgrammaticallyExample extends App {
RemoteRouterConfig(RoundRobinRouter(5), addresses)))
//#remoteRoutees
}
}

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.serialization {

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.testkit
@ -44,4 +44,4 @@ class MySpec(_system: ActorSystem) extends TestKit(_system) with ImplicitSender
}
}
//#plain-spec
//#plain-spec

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.testkit
@ -157,4 +157,4 @@ object TestKitUsageSpec {
}
}
}
//#testkit-usage
//#testkit-usage

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.testkit
@ -206,6 +206,16 @@ class TestkitDocSpec extends AkkaSpec with DefaultTimeout with ImplicitSender {
//#test-special-probe
}
"demonstrate probe watch" in {
import akka.testkit.TestProbe
val target = system.actorFor("/buh")
//#test-probe-watch
val probe = TestProbe()
probe watch target
probe.expectMsgType[Terminated].actor must be(target)
//#test-probe-watch
}
"demonstrate probe reply" in {
import akka.testkit.TestProbe
import scala.concurrent.duration._

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.transactor

View file

@ -1,5 +1,5 @@
/**
* Copyright (C) 2009-2012 Typesafe Inc. <http://www.typesafe.com>
* Copyright (C) 2009-2013 Typesafe Inc. <http://www.typesafe.com>
*/
package docs.zeromq

View file

@ -129,6 +129,11 @@ Note that ``thread-pool-executor`` configuration as per the above ``my-thread-po
NOT applicable. This is because every actor will have its own thread pool when using ``PinnedDispatcher``,
and that pool will have only one thread.
Note that it's not guaranteed that the *same* thread is used over time, since the core pool timeout
is used for ``PinnedDispatcher`` to keep resource usage down in case of idle actors. To use the same
thread all the time you need to add ``thread-pool-executor.allow-core-timeout=off`` to the
configuration of the ``PinnedDispatcher``.
Mailboxes
---------

View file

@ -5,22 +5,23 @@
Scheduler (Scala)
###################
Sometimes the need for making things happen in the future arises, and where do you go look then?
Look no further than ``ActorSystem``! There you find the :meth:`scheduler` method that returns an instance
of akka.actor.Scheduler, this instance is unique per ActorSystem and is used internally for scheduling things
to happen at specific points in time. Please note that the scheduled tasks are executed by the default
``MessageDispatcher`` of the ``ActorSystem``.
Sometimes the need for making things happen in the future arises, and where do
you go look then? Look no further than ``ActorSystem``! There you find the
:meth:`scheduler` method that returns an instance of
:class:`akka.actor.Scheduler`, this instance is unique per ActorSystem and is
used internally for scheduling things to happen at specific points in time.
You can schedule sending of messages to actors and execution of tasks (functions or Runnable).
You will get a ``Cancellable`` back that you can call :meth:`cancel` on to cancel the execution of the
scheduled operation.
You can schedule sending of messages to actors and execution of tasks
(functions or Runnable). You will get a ``Cancellable`` back that you can call
:meth:`cancel` on to cancel the execution of the scheduled operation.
.. warning::
The default implementation of ``Scheduler`` used by Akka is based on the Netty ``HashedWheelTimer``.
It does not execute tasks at the exact time, but on every tick, it will run everything that is overdue.
The accuracy of the default Scheduler can be modified by the "ticks-per-wheel" and "tick-duration" configuration
properties. For more information, see: `HashedWheelTimers <http://www.cse.wustl.edu/~cdgill/courses/cs6874/TimingWheels.ppt>`_.
The default implementation of ``Scheduler`` used by Akka is based on job
buckets which are emptied according to a fixed schedule. It does not
execute tasks at the exact time, but on every tick, it will run everything
that is (over)due. The accuracy of the default Scheduler can be modified
by the ``akka.scheduler.tick-duration`` configuration property.
Some examples
-------------
@ -44,16 +45,26 @@ From ``akka.actor.ActorSystem``
The Scheduler interface
-----------------------
The actual scheduler implementation is loaded reflectively upon
:class:`ActorSystem` start-up, which means that it is possible to provide a
different one using the ``akka.scheduler.implementation`` configuration
property. The referenced class must implement the following interface:
.. includecode:: ../../../akka-actor/src/main/scala/akka/actor/Scheduler.scala
:include: scheduler
The Cancellable interface
-------------------------
This allows you to ``cancel`` something that has been scheduled for execution.
Scheduling a task will result in a :class:`Cancellable` (or throw an
:class:`IllegalStateException` if attempted after the schedulers shutdown).
This allows you to cancel something that has been scheduled for execution.
.. warning::
This does not abort the execution of the task, if it had already been started.
This does not abort the execution of the task, if it had already been
started. Check the return value of ``cancel`` to detect whether the
scheduled task was canceled or will (eventually) have run.
.. includecode:: ../../../akka-actor/src/main/scala/akka/actor/Scheduler.scala
:include: cancellable

View file

@ -446,6 +446,23 @@ facilities with your own checks and choosing an intuitive name for it. In real
life your code will probably be a bit more complicated than the example given
above; just use the power!
.. warning::
Any message send from a ``TestProbe`` to another actor which runs on the
CallingThreadDispatcher runs the risk of dead-lock, if that other actor might
also send to this probe. The implementation of :meth:`TestProbe.watch` and
:meth:`TestProbe.unwatch` will also send a message to the watchee, which
means that it is dangerous to try watching e.g. :class:`TestActorRef` from a
:meth:`TestProbe`.
Watching Other Actors from Probes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A :class:`TestKit` can register itself for DeathWatch of any other actor:
.. includecode:: code/docs/testkit/TestkitDocSpec.scala
:include: test-probe-watch
Replying to Messages Received by Probes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -597,6 +614,28 @@ production.
scenarios, but keep in mind that it has may give false negatives as well as
false positives.
Thread Interruptions
--------------------
If the CallingThreadDispatcher sees that the current thread has its
``isInterrupted()`` flag set when message processing returns, it will throw an
:class:`InterruptedException` after finishing all its processing (i.e. all
messages which need processing as described above are processed before this
happens). As :meth:`tell` cannot throw exceptions due to its contract, this
exception will then be caught and logged, and the threads interrupted status
will be set again.
If during message processing an :class:`InterruptedException` is thrown then it
will be caught inside the CallingThreadDispatchers message handling loop, the
threads interrupted flag will be set and processing continues normally.
.. note::
The summary of these two paragraphs is that if the current thread is
interrupted while doing work under the CallingThreadDispatcher, then that
will result in the ``isInterrupted`` flag to be ``true`` when the message
send returns and no :class:`InterruptedException` will be thrown.
Benefits
--------