+doc #18012 add handleWithAsync documentation + examples
This commit is contained in:
parent
4fe85b8b56
commit
b2c38444b3
2 changed files with 124 additions and 2 deletions
|
|
@ -102,4 +102,42 @@ static methods. The referenced method must be publicly accessible.
|
|||
Deferring Result Creation
|
||||
-------------------------
|
||||
|
||||
TODO
|
||||
Sometimes a handler cannot directly complete the request but needs to do some processing asynchronously. In this case
|
||||
the completion of a request needs to be deferred until the result has been generated. This is supported by the routing
|
||||
DSL in two ways: either you can use one of the ``handleWithAsyncN`` methods passing an ``AsyncHandlerN`` which
|
||||
returns a ``Future<RouteResult>``, i.e. an eventual ``RouteResult``, or you can also use a regular handler as shown
|
||||
above and use ``RequestContext.completeWith`` for completion which takes an ``Future<RouteResult>`` as an argument.
|
||||
|
||||
This is demonstrated in the following example. Consider a asynchronous service defined like this
|
||||
(making use of Java 8 lambdas):
|
||||
|
||||
.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
|
||||
:include: async-service-definition
|
||||
|
||||
Here the calculator runs the actual calculation in the background and only eventually returns the result. The HTTP
|
||||
service should provide a front-end to that service without having to block while waiting for the results. As explained
|
||||
above this can be done in two ways.
|
||||
|
||||
First, you can use ``handleWithAsyncN`` to be able to return a ``Future<RouteResult>``:
|
||||
|
||||
.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
|
||||
:include: async-handler-1
|
||||
|
||||
The handler invokes the service and then maps the calculation result to a ``RouteResult`` using ``Future.map`` and
|
||||
returns the resulting ``Future<RouteResult>``.
|
||||
|
||||
Otherwise, you can also still use ``handleWithN`` and use ``RequestContext.completeWith`` to "convert" a
|
||||
``Future<RouteResult>`` into a ``RouteResult`` as shown here:
|
||||
|
||||
.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
|
||||
:include: async-handler-2
|
||||
|
||||
Using this style, you can decide in your handler if you want to return a direct synchronous result or if you need
|
||||
to defer completion.
|
||||
|
||||
Both alternatives will not block and show the same runtime behavior.
|
||||
|
||||
Here's the complete example:
|
||||
|
||||
.. includecode:: /../../akka-http-tests-java8/src/test/java/docs/http/javadsl/server/HandlerExampleDocTest.java
|
||||
:include: async-example-full
|
||||
|
|
|
|||
|
|
@ -4,14 +4,19 @@
|
|||
|
||||
package docs.http.javadsl.server;
|
||||
|
||||
import akka.dispatch.Futures;
|
||||
import akka.dispatch.Mapper;
|
||||
import akka.http.javadsl.model.HttpRequest;
|
||||
import akka.http.javadsl.server.*;
|
||||
import akka.http.javadsl.server.values.Parameters;
|
||||
import akka.http.javadsl.server.values.PathMatchers;
|
||||
import akka.http.javadsl.testkit.JUnitRouteTest;
|
||||
import akka.http.javadsl.testkit.TestRoute;
|
||||
import akka.japi.function.Function;
|
||||
import org.junit.Test;
|
||||
import scala.concurrent.ExecutionContext;
|
||||
import scala.concurrent.Future;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
public class HandlerExampleDocTest extends JUnitRouteTest {
|
||||
@Test
|
||||
|
|
@ -212,4 +217,83 @@ public class HandlerExampleDocTest extends JUnitRouteTest {
|
|||
.assertEntity("x * y = 115");
|
||||
//#reflective-example-full
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeferredResultAsyncHandler() {
|
||||
//#async-example-full
|
||||
//#async-service-definition
|
||||
class CalculatorService {
|
||||
public Future<Integer> multiply(final int x, final int y, ExecutionContext ec) {
|
||||
return akka.dispatch.Futures.future(() -> x * y, ec);
|
||||
}
|
||||
|
||||
public Future<Integer> add(final int x, final int y, ExecutionContext ec) {
|
||||
return akka.dispatch.Futures.future(() -> x + y, ec);
|
||||
}
|
||||
}
|
||||
//#async-service-definition
|
||||
|
||||
class TestHandler extends akka.http.javadsl.server.AllDirectives {
|
||||
RequestVal<Integer> xParam = Parameters.intValue("x");
|
||||
RequestVal<Integer> yParam = Parameters.intValue("y");
|
||||
|
||||
//#async-handler-1
|
||||
// would probably be injected or passed at construction time in real code
|
||||
CalculatorService calculatorService = new CalculatorService();
|
||||
public Future<RouteResult> multiplyAsync(final RequestContext ctx, int x, int y) {
|
||||
Future<Integer> result = calculatorService.multiply(x, y, ctx.executionContext());
|
||||
Mapper<Integer, RouteResult> func = new Mapper<Integer, RouteResult>() {
|
||||
@Override
|
||||
public RouteResult apply(Integer product) {
|
||||
return ctx.complete("x * y = " + product);
|
||||
}
|
||||
}; // cannot be written as lambda, unfortunately
|
||||
return result.map(func, ctx.executionContext());
|
||||
}
|
||||
Route multiplyAsyncRoute =
|
||||
path("multiply").route(
|
||||
handleWithAsync2(xParam, yParam, this::multiplyAsync)
|
||||
);
|
||||
//#async-handler-1
|
||||
|
||||
//#async-handler-2
|
||||
public RouteResult addAsync(final RequestContext ctx, int x, int y) {
|
||||
Future<Integer> result = calculatorService.add(x, y, ctx.executionContext());
|
||||
Mapper<Integer, RouteResult> func = new Mapper<Integer, RouteResult>() {
|
||||
@Override
|
||||
public RouteResult apply(Integer sum) {
|
||||
return ctx.complete("x + y = " + sum);
|
||||
}
|
||||
}; // cannot be written as lambda, unfortunately
|
||||
return ctx.completeWith(result.map(func, ctx.executionContext()));
|
||||
}
|
||||
Route addAsyncRoute =
|
||||
path("add").route(
|
||||
handleWith2(xParam, yParam, this::addAsync)
|
||||
);
|
||||
//#async-handler-2
|
||||
|
||||
Route createRoute() {
|
||||
return route(
|
||||
get(
|
||||
pathPrefix("calculator").route(
|
||||
multiplyAsyncRoute,
|
||||
addAsyncRoute
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// testing code
|
||||
TestRoute r = testRoute(new TestHandler().createRoute());
|
||||
r.run(HttpRequest.GET("/calculator/multiply?x=12&y=42"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("x * y = 504");
|
||||
|
||||
r.run(HttpRequest.GET("/calculator/add?x=23&y=5"))
|
||||
.assertStatusCode(200)
|
||||
.assertEntity("x + y = 28");
|
||||
//#async-example-full
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue