Merge branch 'wip-1581-patterns-ask'
This commit is contained in:
commit
2a0c4ca145
126 changed files with 980 additions and 415 deletions
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
---------------
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue