Merge branch 'wip-1581-patterns-ask'

This commit is contained in:
Roland 2012-01-23 18:35:30 +01:00
commit 2a0c4ca145
126 changed files with 980 additions and 415 deletions

View file

@ -13,6 +13,7 @@ import akka.actor.Props;
import akka.actor.Terminated;
import akka.actor.UntypedActor;
import akka.dispatch.Await;
import static akka.pattern.Patterns.ask;
import akka.util.Duration;
import akka.testkit.AkkaSpec;
import akka.testkit.TestProbe;
@ -160,19 +161,19 @@ public class FaultHandlingTestBase {
//#create
Props superprops = new Props(Supervisor.class);
ActorRef supervisor = system.actorOf(superprops, "supervisor");
ActorRef child = (ActorRef) Await.result(supervisor.ask(new Props(Child.class), 5000), timeout);
ActorRef child = (ActorRef) Await.result(ask(supervisor, new Props(Child.class), 5000), timeout);
//#create
//#resume
child.tell(42);
assert Await.result(child.ask("get", 5000), timeout).equals(42);
assert Await.result(ask(child, "get", 5000), timeout).equals(42);
child.tell(new ArithmeticException());
assert Await.result(child.ask("get", 5000), timeout).equals(42);
assert Await.result(ask(child, "get", 5000), timeout).equals(42);
//#resume
//#restart
child.tell(new NullPointerException());
assert Await.result(child.ask("get", 5000), timeout).equals(0);
assert Await.result(ask(child, "get", 5000), timeout).equals(0);
//#restart
//#stop
@ -183,9 +184,9 @@ public class FaultHandlingTestBase {
//#stop
//#escalate-kill
child = (ActorRef) Await.result(supervisor.ask(new Props(Child.class), 5000), timeout);
child = (ActorRef) Await.result(ask(supervisor, new Props(Child.class), 5000), timeout);
probe.watch(child);
assert Await.result(child.ask("get", 5000), timeout).equals(0);
assert Await.result(ask(child, "get", 5000), timeout).equals(0);
child.tell(new Exception());
probe.expectMsg(new Terminated(child));
//#escalate-kill
@ -193,11 +194,11 @@ public class FaultHandlingTestBase {
//#escalate-restart
superprops = new Props(Supervisor2.class);
supervisor = system.actorOf(superprops, "supervisor2");
child = (ActorRef) Await.result(supervisor.ask(new Props(Child.class), 5000), timeout);
child = (ActorRef) Await.result(ask(supervisor, new Props(Child.class), 5000), timeout);
child.tell(23);
assert Await.result(child.ask("get", 5000), timeout).equals(23);
assert Await.result(ask(child, "get", 5000), timeout).equals(23);
child.tell(new Exception());
assert Await.result(child.ask("get", 5000), timeout).equals(0);
assert Await.result(ask(child, "get", 5000), timeout).equals(0);
//#escalate-restart
//#testkit
}

View file

@ -11,6 +11,7 @@ import akka.actor.Props;
//#import-future
import akka.dispatch.Future;
import akka.dispatch.Futures;
import akka.dispatch.Await;
import akka.util.Duration;
import akka.util.Timeout;
@ -36,6 +37,17 @@ import akka.util.Duration;
import akka.actor.ActorTimeoutException;
//#import-gracefulStop
//#import-askPipeTo
import static akka.pattern.Patterns.ask;
import static akka.pattern.Patterns.pipeTo;
import akka.dispatch.Future;
import akka.dispatch.Futures;
import akka.util.Duration;
import akka.util.Timeout;
import java.util.concurrent.TimeUnit;
import java.util.ArrayList;
//#import-askPipeTo
import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.actor.UntypedActorFactory;
@ -44,7 +56,10 @@ import akka.dispatch.MessageDispatcher;
import org.junit.Test;
import scala.Option;
import java.lang.Object;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.TimeUnit;
import akka.pattern.Patterns;
import static org.junit.Assert.*;
@ -123,7 +138,7 @@ public class UntypedActorDocTestBase {
}), "myactor");
//#using-ask
Future<Object> future = myActor.ask("Hello", 1000);
Future<Object> future = Patterns.ask(myActor, "Hello", 1000);
Object result = Await.result(future, Duration.create(1, TimeUnit.SECONDS));
//#using-ask
system.shutdown();
@ -175,7 +190,7 @@ public class UntypedActorDocTestBase {
public void useWatch() {
ActorSystem system = ActorSystem.create("MySystem");
ActorRef myActor = system.actorOf(new Props(WatchActor.class));
Future<Object> future = myActor.ask("kill", 1000);
Future<Object> future = Patterns.ask(myActor, "kill", 1000);
assert Await.result(future, Duration.parse("1 second")).equals("finished");
system.shutdown();
}
@ -196,6 +211,43 @@ public class UntypedActorDocTestBase {
//#gracefulStop
system.shutdown();
}
class Result {
final int x;
final String s;
public Result(int x, String s) {
this.x = x;
this.s = s;
}
}
@Test
public void usePatternsAskPipeTo() {
ActorSystem system = ActorSystem.create("MySystem");
ActorRef actorA = system.actorOf(new Props(MyUntypedActor.class));
ActorRef actorB = system.actorOf(new Props(MyUntypedActor.class));
ActorRef actorC = system.actorOf(new Props(MyUntypedActor.class));
//#ask-pipeTo
final Timeout t = new Timeout(Duration.create(5, TimeUnit.SECONDS));
final ArrayList<Future<Object>> futures = new ArrayList<Future<Object>>();
futures.add(ask(actorA, "request", 1000)); // using 1000ms timeout
futures.add(ask(actorB, "reqeest", t)); // using timeout from above
final Future<Iterable<Object>> aggregate = Futures.sequence(futures, system.dispatcher());
final Future<Result> transformed = aggregate.map(new akka.japi.Function<Iterable<Object>, Result>() {
public Result apply(Iterable<Object> coll) {
final Iterator<Object> it = coll.iterator();
final String s = (String) it.next();
final int x = (Integer) it.next();
return new Result(x, s);
}
});
pipeTo(transformed, actorC);
//#ask-pipeTo
}
public static class MyActor extends UntypedActor {

View file

@ -53,9 +53,9 @@ import akka.actor.Status.Failure;
import akka.actor.ActorSystem;
import akka.actor.UntypedActor;
import akka.actor.ActorRef;
import akka.docs.actor.MyUntypedActor;
import akka.actor.Props;
import akka.dispatch.Futures;
import akka.pattern.Patterns;
import static org.junit.Assert.*;
@ -79,7 +79,7 @@ public class FutureDocTestBase {
String msg = "hello";
//#ask-blocking
Timeout timeout = system.settings().ActorTimeout();
Future<Object> future = actor.ask(msg, timeout);
Future<Object> future = Patterns.ask(actor, msg, timeout);
String result = (String) Await.result(future, timeout.duration());
//#ask-blocking
assertEquals("HELLO", result);

View file

@ -19,6 +19,7 @@ import akka.dispatch.Await;
import akka.dispatch.Future;
import akka.testkit.AkkaSpec;
import com.typesafe.config.ConfigFactory;
import static akka.pattern.Patterns.ask;
import static akka.docs.jrouting.CustomRouterDocTestBase.DemocratActor;
import static akka.docs.jrouting.CustomRouterDocTestBase.RepublicanActor;
@ -48,8 +49,8 @@ public class CustomRouterDocTestBase {
routedActor.tell(DemocratVote);
routedActor.tell(RepublicanVote);
Timeout timeout = new Timeout(Duration.parse("1 seconds"));
Future<Object> democratsResult = routedActor.ask(DemocratCountResult, timeout);
Future<Object> republicansResult = routedActor.ask(RepublicanCountResult, timeout);
Future<Object> democratsResult = ask(routedActor, DemocratCountResult, timeout);
Future<Object> republicansResult = ask(routedActor, RepublicanCountResult, timeout);
assertEquals(3, Await.result(democratsResult, timeout.duration()));
assertEquals(2, Await.result(republicansResult, timeout.duration()));

View file

@ -55,8 +55,8 @@ public class ParentActor extends UntypedActor {
new Props(FibonacciActor.class).withRouter(new ScatterGatherFirstCompletedRouter(5, Duration
.parse("2 seconds"))), "router");
Timeout timeout = getContext().system().settings().ActorTimeout();
Future<Object> futureResult = scatterGatherFirstCompletedRouter.ask(new FibonacciActor.FibonacciNumber(10),
timeout);
Future<Object> futureResult = akka.pattern.Patterns.ask(
scatterGatherFirstCompletedRouter, new FibonacciActor.FibonacciNumber(10), timeout);
int result = (Integer) Await.result(futureResult, timeout.duration());
//#scatterGatherFirstCompletedRouter
System.out.println(String.format("The result of calculating Fibonacci for 10 is %d", result));

View file

@ -10,6 +10,7 @@ import org.junit.Test;
//#imports
import akka.actor.*;
import akka.dispatch.Await;
import static akka.pattern.Patterns.ask;
import akka.transactor.Coordinated;
import akka.util.Duration;
import akka.util.Timeout;
@ -30,7 +31,7 @@ public class TransactorDocTest {
counter1.tell(new Coordinated(new Increment(counter2), timeout));
Integer count = (Integer) Await.result(counter1.ask("GetCount", timeout), timeout.duration());
Integer count = (Integer) Await.result(ask(counter1, "GetCount", timeout), timeout.duration());
//#coordinated-example
assertEquals(count, new Integer(1));
@ -71,7 +72,7 @@ public class TransactorDocTest {
counter.tell(coordinated.coordinate(new Increment()));
coordinated.await();
Integer count = (Integer) Await.result(counter.ask("GetCount", timeout), timeout.duration());
Integer count = (Integer) Await.result(ask(counter, "GetCount", timeout), timeout.duration());
assertEquals(count, new Integer(1));
system.shutdown();
@ -88,10 +89,10 @@ public class TransactorDocTest {
friendlyCounter.tell(coordinated.coordinate(new Increment(friend)));
coordinated.await();
Integer count1 = (Integer) Await.result(friendlyCounter.ask("GetCount", timeout), timeout.duration());
Integer count1 = (Integer) Await.result(ask(friendlyCounter, "GetCount", timeout), timeout.duration());
assertEquals(count1, new Integer(1));
Integer count2 = (Integer) Await.result(friend.ask("GetCount", timeout), timeout.duration());
Integer count2 = (Integer) Await.result(ask(friend, "GetCount", timeout), timeout.duration());
assertEquals(count2, new Integer(1));
system.shutdown();

View file

@ -316,26 +316,37 @@ If invoked without the sender parameter the sender will be
Ask: Send-And-Receive-Future
----------------------------
Using ``?`` will send a message to the receiving Actor asynchronously and
will immediately return a :class:`Future` which will be completed with
an ``akka.actor.AskTimeoutException`` after the specified timeout:
The ``ask`` pattern involves actors as well as futures, hence it is offered as
a use pattern rather than a method on :class:`ActorRef`:
.. code-block:: java
.. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java#import-askPipeTo
long timeoutMillis = 1000;
Future future = actorRef.ask("Hello", timeoutMillis);
.. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java#ask-pipeTo
The receiving actor should reply to this message, which will complete the
future with the reply message as value; ``getSender.tell(result)``.
This example demonstrates ``ask`` together with the ``pipeTo`` pattern on
futures, because this is likely to be a common combination. Please note that
all of the above is completely non-blocking and asynchronous: ``ask`` produces
a :class:`Future`, two of which are composed into a new future using the
:meth:`Futures.sequence` and :meth:`map` methods and then ``pipeTo`` installs
an ``onComplete``-handler on the future to effect the submission of the
aggregated :class:`Result` to another actor.
Using ``ask`` will send a message to the receiving Actor as with ``tell``, and
the receiving actor must reply with ``getSender().tell(reply)`` in order to
complete the returned :class:`Future` with a value. The ``ask`` operation
involves creating an internal actor for handling this reply, which needs to
have a timeout after which it is destroyed in order not to leak resources; see
more below.
To complete the future with an exception you need send a Failure message to the sender.
This is not done automatically when an actor throws an exception while processing a
This is *not done automatically* when an actor throws an exception while processing a
message.
.. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java#reply-exception
If the actor does not complete the future, it will expire after the timeout period,
specified as parameter to the ``ask`` method.
specified as parameter to the ``ask`` method; this will complete the
:class:`Future` with an :class:`AskTimeoutException`.
See :ref:`futures-java` for more information on how to await or query a
future.
@ -354,15 +365,6 @@ Gives you a way to avoid blocking.
there is not yet a way to detect these illegal accesses at compile time. See also:
:ref:`jmm-shared-state`
The future returned from the ``ask`` method can conveniently be passed around or
chained with further processing steps, but sometimes you just need the value,
even if that entails waiting for it (but keep in mind that waiting inside an
actor is prone to dead-locks, e.g. if obtaining the result depends on
processing another message on this actor).
.. includecode:: code/akka/docs/actor/UntypedActorDocTestBase.java
:include: import-future,using-ask
Forward message
---------------