diff --git a/akka-docs/rst/java/code/docs/future/FutureDocTestBase.java b/akka-docs/rst/java/code/docs/future/FutureDocTestBase.java index 5e9f70b8b0..fb49a9a48d 100644 --- a/akka-docs/rst/java/code/docs/future/FutureDocTestBase.java +++ b/akka-docs/rst/java/code/docs/future/FutureDocTestBase.java @@ -79,6 +79,21 @@ public class FutureDocTestBase { system.shutdown(); } + public final static class PrintResult extends OnSuccess { + @Override public final void onSuccess(T t) { + // print t + } + } + + public final static class Demo { + //#print-result + public final static class PrintResult extends OnSuccess { + @Override public final void onSuccess(T t) { + System.out.println(t); + } + } + //#print-result + } @SuppressWarnings("unchecked") @Test public void useCustomExecutionContext() throws Exception { ExecutorService yourExecutorServiceGoesHere = Executors.newSingleThreadExecutor(); //#diy-execution-context @@ -102,6 +117,9 @@ public class FutureDocTestBase { Future future = Patterns.ask(actor, msg, timeout); String result = (String) Await.result(future, timeout.duration()); //#ask-blocking + //#pipe-to + akka.pattern.Patterns.pipe(future, system.dispatcher()).to(actor); + //#pipe-to assertEquals("HELLO", result); } @@ -113,9 +131,11 @@ public class FutureDocTestBase { return "Hello" + "World"; } }, system.dispatcher()); - String result = (String) Await.result(f, Duration.create(5, SECONDS)); + + f.onSuccess(new PrintResult(), system.dispatcher()); //#future-eval - assertEquals("HelloWorld", result); + String result = (String) Await.result(f, Duration.create(5, SECONDS)); + assertEquals("HelloWorld", result); } @Test @@ -135,9 +155,10 @@ public class FutureDocTestBase { } }, ec); + f2.onSuccess(new PrintResult(), system.dispatcher()); + //#map int result = Await.result(f2, Duration.create(5, SECONDS)); assertEquals(10, result); - //#map } @Test @@ -158,6 +179,7 @@ public class FutureDocTestBase { } }, ec); + f2.onSuccess(new PrintResult(), system.dispatcher()); //#map2 int result = Await.result(f2, Duration.create(5, SECONDS)); assertEquals(10, result); @@ -174,7 +196,8 @@ public class FutureDocTestBase { } }, ec); - Thread.sleep(100); + // Thread.sleep is only here to prove a point + Thread.sleep(100); // Do not use this in your code Future f2 = f1.map(new Mapper() { public Integer apply(String s) { @@ -182,6 +205,7 @@ public class FutureDocTestBase { } }, ec); + f2.onSuccess(new PrintResult(), system.dispatcher()); //#map3 int result = Await.result(f2, Duration.create(5, SECONDS)); assertEquals(10, result); @@ -208,6 +232,7 @@ public class FutureDocTestBase { } }, ec); + f2.onSuccess(new PrintResult(), system.dispatcher()); //#flat-map int result = Await.result(f2, Duration.create(5, SECONDS)); assertEquals(10, result); @@ -238,8 +263,9 @@ public class FutureDocTestBase { } }, ec); - long result = Await.result(futureSum, Duration.create(5, SECONDS)); + futureSum.onSuccess(new PrintResult(), system.dispatcher()); //#sequence + long result = Await.result(futureSum, Duration.create(5, SECONDS)); assertEquals(3L, result); } @@ -262,9 +288,10 @@ public class FutureDocTestBase { }, ec); //Returns the sequence of strings as upper case + futureResult.onSuccess(new PrintResult>(), system.dispatcher()); + //#traverse Iterable result = Await.result(futureResult, Duration.create(5, SECONDS)); assertEquals(Arrays.asList("A", "B", "C"), result); - //#traverse } @Test @@ -286,9 +313,10 @@ public class FutureDocTestBase { return r + t; //Just concatenate } }, ec); - String result = Await.result(resultFuture, Duration.create(5, SECONDS)); - //#fold + resultFuture.onSuccess(new PrintResult(), system.dispatcher()); + //#fold + String result = Await.result(resultFuture, Duration.create(5, SECONDS)); assertEquals("ab", result); } @@ -310,8 +338,9 @@ public class FutureDocTestBase { } }, ec); - Object result = Await.result(resultFuture, Duration.create(5, SECONDS)); + resultFuture.onSuccess(new PrintResult(), system.dispatcher()); //#reduce + Object result = Await.result(resultFuture, Duration.create(5, SECONDS)); assertEquals("ab", result); } @@ -399,9 +428,11 @@ public class FutureDocTestBase { throw problem; } }, ec); + + future.onSuccess(new PrintResult(), system.dispatcher()); + //#recover int result = Await.result(future, Duration.create(5, SECONDS)); assertEquals(result, 0); - //#recover } @Test @@ -425,9 +456,11 @@ public class FutureDocTestBase { throw problem; } }, ec); + + future.onSuccess(new PrintResult(), system.dispatcher()); + //#try-recover int result = Await.result(future, Duration.create(5, SECONDS)); assertEquals(result, 0); - //#try-recover } @Test @@ -497,9 +530,10 @@ public class FutureDocTestBase { } }, ec); + future3.onSuccess(new PrintResult(), system.dispatcher()); + //#zip String result = Await.result(future3, Duration.create(5, SECONDS)); assertEquals("foo bar", result); - //#zip } { @@ -509,9 +543,10 @@ public class FutureDocTestBase { Future future3 = Futures.successful("bar"); // Will have "bar" in this case Future future4 = future1.fallbackTo(future2).fallbackTo(future3); + future4.onSuccess(new PrintResult(), system.dispatcher()); + //#fallback-to String result = Await.result(future4, Duration.create(5, SECONDS)); assertEquals("bar", result); - //#fallback-to } } diff --git a/akka-docs/rst/java/futures.rst b/akka-docs/rst/java/futures.rst index 137f0badac..f643155bc3 100644 --- a/akka-docs/rst/java/futures.rst +++ b/akka-docs/rst/java/futures.rst @@ -47,6 +47,17 @@ Alternatives to blocking are discussed further within this documentation. Also note that the ``Future`` returned by an ``UntypedActor`` is a ``Future`` since an ``UntypedActor`` is dynamic. That is why the cast to ``String`` is used in the above sample. +.. warning:: + + ``Await.result`` and ``Await.ready`` are provided for exceptional situations where you **must** block, + a good rule of thumb is to only use them if you know why you **must** block. For all other cases, use + asynchronous composition as described below. + +To send the result of a ``Future`` to an ``Actor``, you can use the ``pipe`` construct: + +.. includecode:: code/docs/future/FutureDocTestBase.java + :include: pipe-to + Use Directly ------------ @@ -75,6 +86,11 @@ Or failures: .. includecode:: code/docs/future/FutureDocTestBase.java :include: failed +For these examples ``PrintResult`` is defined as follows: + +.. includecode:: code/docs/future/FutureDocTestBase.java + :include: print-result + Functional Futures ------------------ diff --git a/akka-docs/rst/scala/code/docs/future/FutureDocSpec.scala b/akka-docs/rst/scala/code/docs/future/FutureDocSpec.scala index 6e6a3521d1..48feec13d9 100644 --- a/akka-docs/rst/scala/code/docs/future/FutureDocSpec.scala +++ b/akka-docs/rst/scala/code/docs/future/FutureDocSpec.scala @@ -39,6 +39,9 @@ object FutureDocSpec { class FutureDocSpec extends AkkaSpec { import FutureDocSpec._ import system.dispatcher + + val println: PartialFunction[Any, Unit] = { case _ ⇒ } + "demonstrate usage custom ExecutionContext" in { val yourExecutorServiceGoesHere = java.util.concurrent.Executors.newSingleThreadExecutor() //#diy-execution-context @@ -68,6 +71,12 @@ class FutureDocSpec extends AkkaSpec { val future = actor ? msg // enabled by the “ask” import val result = Await.result(future, timeout.duration).asInstanceOf[String] //#ask-blocking + + //#pipe-to + import akka.pattern.pipe + future pipeTo actor + //#pipe-to + result must be("HELLO") } @@ -93,9 +102,9 @@ class FutureDocSpec extends AkkaSpec { val future = Future { "Hello" + "World" } - val result = Await.result(future, 1 second) + future foreach println //#future-eval - result must be("HelloWorld") + Await.result(future, 1 second) must be("HelloWorld") } "demonstrate usage of map" in { @@ -106,10 +115,11 @@ class FutureDocSpec extends AkkaSpec { val f2 = f1 map { x ⇒ x.length } + f2 foreach println + //#map val result = Await.result(f2, 1 second) result must be(10) f1.value must be(Some(Success("HelloWorld"))) - //#map } "demonstrate wrong usage of nested map" in { @@ -123,6 +133,7 @@ class FutureDocSpec extends AkkaSpec { x.length * y } } + f3 foreach println //#wrong-nested-map Await.ready(f3, 1 second) } @@ -138,25 +149,30 @@ class FutureDocSpec extends AkkaSpec { x.length * y } } + f3 foreach println + //#flat-map val result = Await.result(f3, 1 second) result must be(30) - //#flat-map } "demonstrate usage of filter" in { //#filter val future1 = Future.successful(4) val future2 = future1.filter(_ % 2 == 0) - val result = Await.result(future2, 1 second) - result must be(4) + + future2 foreach println val failedFilter = future1.filter(_ % 2 == 1).recover { // When filter fails, it will have a java.util.NoSuchElementException case m: NoSuchElementException ⇒ 0 } + + failedFilter foreach println + //#filter + val result = Await.result(future2, 1 second) + result must be(4) val result2 = Await.result(failedFilter, 1 second) result2 must be(0) //Can only be 0 when there was a MatchError - //#filter } "demonstrate usage of for comprehension" in { @@ -171,9 +187,10 @@ class FutureDocSpec extends AkkaSpec { // Note that the execution of futures a, b, and c // are not done in parallel. + f foreach println + //#for-comprehension val result = Await.result(f, 1 second) result must be(24) - //#for-comprehension } "demonstrate wrong way of composing" in { @@ -220,8 +237,9 @@ class FutureDocSpec extends AkkaSpec { c ← ask(actor3, (a + b)).mapTo[Int] } yield c - val result = Await.result(f3, 1 second).asInstanceOf[Int] + f3 foreach println //#composing + val result = Await.result(f3, 1 second).asInstanceOf[Int] result must be(3) } @@ -236,25 +254,28 @@ class FutureDocSpec extends AkkaSpec { val futureList = Future.sequence(listOfFutures) // Find the sum of the odd numbers - val oddSum = Await.result(futureList.map(_.sum), 1 second).asInstanceOf[Int] - oddSum must be(10000) + val oddSum = futureList.map(_.sum) + oddSum foreach println //#sequence-ask + Await.result(oddSum, 1 second).asInstanceOf[Int] must be(10000) } "demonstrate usage of sequence" in { //#sequence val futureList = Future.sequence((1 to 100).toList.map(x ⇒ Future(x * 2 - 1))) - val oddSum = Await.result(futureList.map(_.sum), 1 second).asInstanceOf[Int] - oddSum must be(10000) + val oddSum = futureList.map(_.sum) + oddSum foreach println //#sequence + Await.result(oddSum, 1 second).asInstanceOf[Int] must be(10000) } "demonstrate usage of traverse" in { //#traverse val futureList = Future.traverse((1 to 100).toList)(x ⇒ Future(x * 2 - 1)) - val oddSum = Await.result(futureList.map(_.sum), 1 second).asInstanceOf[Int] - oddSum must be(10000) + val oddSum = futureList.map(_.sum) + oddSum foreach println //#traverse + Await.result(oddSum, 1 second).asInstanceOf[Int] must be(10000) } "demonstrate usage of fold" in { @@ -262,8 +283,9 @@ class FutureDocSpec extends AkkaSpec { // Create a sequence of Futures val futures = for (i ← 1 to 1000) yield Future(i * 2) val futureSum = Future.fold(futures)(0)(_ + _) - Await.result(futureSum, 1 second) must be(1001000) + futureSum foreach println //#fold + Await.result(futureSum, 1 second) must be(1001000) } "demonstrate usage of reduce" in { @@ -271,8 +293,9 @@ class FutureDocSpec extends AkkaSpec { // Create a sequence of Futures val futures = for (i ← 1 to 1000) yield Future(i * 2) val futureSum = Future.reduce(futures)(_ + _) - Await.result(futureSum, 1 second) must be(1001000) + futureSum foreach println //#reduce + Await.result(futureSum, 1 second) must be(1001000) } "demonstrate usage of recover" in { @@ -283,6 +306,7 @@ class FutureDocSpec extends AkkaSpec { val future = akka.pattern.ask(actor, msg1) recover { case e: ArithmeticException ⇒ 0 } + future foreach println //#recover Await.result(future, 1 second) must be(0) } @@ -297,6 +321,7 @@ class FutureDocSpec extends AkkaSpec { case foo: IllegalArgumentException ⇒ Future.failed[Int](new IllegalStateException("All br0ken!")) } + future foreach println //#try-recover Await.result(future, 1 second) must be(0) } @@ -306,6 +331,7 @@ class FutureDocSpec extends AkkaSpec { val future2 = Future { "bar" } //#zip val future3 = future1 zip future2 map { case (a, b) ⇒ a + " " + b } + future3 foreach println //#zip Await.result(future3, 1 second) must be("foo bar") } @@ -321,6 +347,7 @@ class FutureDocSpec extends AkkaSpec { } andThen { case _ ⇒ watchSomeTV } + result foreach println //#and-then Await.result(result, 1 second) must be("foo bar") } @@ -331,6 +358,7 @@ class FutureDocSpec extends AkkaSpec { val future3 = Future { "pigdog" } //#fallback-to val future4 = future1 fallbackTo future2 fallbackTo future3 + future4 foreach println //#fallback-to Await.result(future4, 1 second) must be("foo") } diff --git a/akka-docs/rst/scala/futures.rst b/akka-docs/rst/scala/futures.rst index 0347d93e4b..6cfb188a6d 100644 --- a/akka-docs/rst/scala/futures.rst +++ b/akka-docs/rst/scala/futures.rst @@ -41,7 +41,7 @@ Use With Actors There are generally two ways of getting a reply from an ``Actor``: the first is by a sent message (``actor ! msg``), which only works if the original sender was an ``Actor``) and the second is through a ``Future``. -Using an ``Actor``\'s ``?`` method to send a message will return a ``Future``. To wait for and retrieve the actual result the simplest method is: +Using an ``Actor``\'s ``?`` method to send a message will return a ``Future``: .. includecode:: code/docs/future/FutureDocSpec.scala :include: ask-blocking @@ -59,6 +59,11 @@ When using non-blocking it is better to use the ``mapTo`` method to safely try t The ``mapTo`` method will return a new ``Future`` that contains the result if the cast was successful, or a ``ClassCastException`` if not. Handling ``Exception``\s will be discussed further within this documentation. +To send the result of a ``Future`` to an ``Actor``, you can use the ``pipe`` construct: + +.. includecode:: code/docs/future/FutureDocSpec.scala + :include: pipe-to + Use Directly ------------ @@ -150,6 +155,12 @@ First an example of using ``Await.result``: .. includecode:: code/docs/future/FutureDocSpec.scala :include: composing-wrong +.. warning:: + + ``Await.result`` and ``Await.ready`` are provided for exceptional situations where you **must** block, + a good rule of thumb is to only use them if you know why you **must** block. For all other cases, use + asynchronous composition as described below. + Here we wait for the results from the first 2 ``Actor``\s before sending that result to the third ``Actor``. We called ``Await.result`` 3 times, which caused our little program to block 3 times before getting our final result. Now compare that to this example: