Merge pull request #19578 from akka/wip-19440-completionStage-RK
#19440 replace Scala Future usage with CompletionStage in javadsl
This commit is contained in:
commit
6ba20ac673
118 changed files with 1646 additions and 1379 deletions
|
|
@ -7,6 +7,25 @@ Migration Guide 2.0.x to 2.4.x
|
|||
General notes
|
||||
=============
|
||||
|
||||
Java DSL now uses Java 8 types: CompletionStage and Optional
|
||||
------------------------------------------------------------
|
||||
|
||||
In order to provide a top-notch Java API we switched from Scala’s Future and Akka’s
|
||||
``akka.japi.Option`` interim solutions to the JDK’s own types for deferred computation
|
||||
and optional results. This has been done throughout Streams & HTTP, most notably changing most
|
||||
materialized types, but also the signature of the ``mapAsync`` combinator and the
|
||||
asynchronous route result combinators in the HTTP DSL.
|
||||
|
||||
The ``akka.pattern`` package has been updated with a new set of implementations within
|
||||
the ``PatternCS`` class that provide the ability to interact between Actors and Futures
|
||||
(or streams) for ``CompletionStage``.
|
||||
|
||||
Should you have the need to use Scala Futures with these new Java APIs please use
|
||||
the ``scala-java8-compat`` library that comes as a dependency of Akka. For more
|
||||
information see `the documentation``_.
|
||||
|
||||
.. _`the documentation`:: https://github.com/scala/scala-java8-compat
|
||||
|
||||
akka.Done and akka.NotUsed replacing Unit and BoxedUnit
|
||||
-------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ type is of the nested module (indicated by the color *red* on the diagram):
|
|||
.. includecode:: ../code/docs/stream/CompositionDocTest.java#mat-combine-1
|
||||
|
||||
Next, we create a composite :class:`Flow` from two smaller components. Here, the second enclosed :class:`Flow` has a
|
||||
materialized type of :class:`Future<OutgoingConnection>`, and we propagate this to the parent by using ``Keep.right()``
|
||||
materialized type of :class:`CompletionStage<OutgoingConnection>`, and we propagate this to the parent by using ``Keep.right()``
|
||||
as the combiner function (indicated by the color *yellow* on the diagram):
|
||||
|
||||
.. includecode:: ../code/docs/stream/CompositionDocTest.java#mat-combine-2
|
||||
|
|
@ -267,7 +267,7 @@ we use ``Keep.both()`` to get a :class:`Pair` of them as the materialized type o
|
|||
|
||||
As the last example, we wire together ``nestedSource`` and ``nestedSink`` and we use a custom combiner function to
|
||||
create a yet another materialized type of the resulting :class:`RunnableGraph`. This combiner function just ignores
|
||||
the :class:`Future<Sink>` part, and wraps the other two values in a custom case class :class:`MyClass`
|
||||
the :class:`CompletionStage<Sink>` part, and wraps the other two values in a custom case class :class:`MyClass`
|
||||
(indicated by color *purple* on the diagram):
|
||||
|
||||
.. includecode:: ../code/docs/stream/CompositionDocTest.java#mat-combine-4a
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ In this recipe we will use the ``grouped`` stream operation that groups incoming
|
|||
size collections (it can be seen as the almost opposite version of the "Flattening a stream of sequences" recipe
|
||||
we showed before). By using a ``grouped(MAX_ALLOWED_SIZE)`` we create a stream of groups
|
||||
with maximum size of ``MaxAllowedSeqSize`` and then we take the first element of this stream by attaching a ``Sink.head()``. What we get is a
|
||||
:class:`Future` containing a sequence with all the elements of the original up to ``MAX_ALLOWED_SIZE`` size (further
|
||||
:class:`CompletionStage` containing a sequence with all the elements of the original up to ``MAX_ALLOWED_SIZE`` size (further
|
||||
elements are dropped).
|
||||
|
||||
.. includecode:: ../code/docs/stream/javadsl/cookbook/RecipeToStrict.java#draining-to-list
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ Assume that we can lookup their email address using:
|
|||
|
||||
.. includecode:: ../code/docs/stream/IntegrationDocTest.java#email-address-lookup2
|
||||
|
||||
The ``Future`` is completed with ``Failure`` if the email is not found.
|
||||
The ``CompletionStage`` is completed normally if the email is not found.
|
||||
|
||||
Transforming the stream of authors to a stream of email addresses by using the ``lookupEmail``
|
||||
service can be done with ``mapAsync`` and we use ``Supervision.getResumingDecider`` to drop
|
||||
|
|
@ -76,4 +76,4 @@ unknown email addresses:
|
|||
.. includecode:: ../code/docs/stream/IntegrationDocTest.java#email-addresses-mapAsync-supervision
|
||||
|
||||
If we would not use ``Resume`` the default stopping strategy would complete the stream
|
||||
with failure on the first ``Future`` that was completed with ``Failure``.
|
||||
with failure on the first ``CompletionStage`` that was completed exceptionally.
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ one actor prepare the work, and then have it be materialized at some completely
|
|||
|
||||
After running (materializing) the ``RunnableGraph`` we get a special container object, the ``MaterializedMap``. Both
|
||||
sources and sinks are able to put specific objects into this map. Whether they put something in or not is implementation
|
||||
dependent. For example a ``FoldSink`` will make a ``Future`` available in this map which will represent the result
|
||||
dependent. For example a ``FoldSink`` will make a ``CompletionStage`` available in this map which will represent the result
|
||||
of the folding process over the stream. In general, a stream can expose multiple materialized values,
|
||||
but it is quite common to be interested in only the value of the Source or the Sink in the stream. For this reason
|
||||
there is a convenience method called ``runWith()`` available for ``Sink``, ``Source`` or ``Flow`` requiring, respectively,
|
||||
|
|
@ -105,7 +105,7 @@ of the given sink or source.
|
|||
|
||||
Since a stream can be materialized multiple times, the ``MaterializedMap`` returned is different for each materialization.
|
||||
In the example below we create two running materialized instance of the stream that we described in the ``runnable``
|
||||
variable, and both materializations give us a different ``Future`` from the map even though we used the same ``sink``
|
||||
variable, and both materializations give us a different ``CompletionStage`` from the map even though we used the same ``sink``
|
||||
to refer to the future:
|
||||
|
||||
.. includecode:: ../code/docs/stream/FlowDocTest.java#stream-reuse
|
||||
|
|
|
|||
|
|
@ -222,7 +222,7 @@ times to acquire the necessary number of outlets.
|
|||
.. includecode:: ../code/docs/stream/FlowGraphDocTest.java#flow-graph-matvalue
|
||||
|
||||
Be careful not to introduce a cycle where the materialized value actually contributes to the materialized value.
|
||||
The following example demonstrates a case where the materialized ``Future`` of a fold is fed back to the fold itself.
|
||||
The following example demonstrates a case where the materialized ``CompletionStage`` of a fold is fed back to the fold itself.
|
||||
|
||||
.. includecode:: ../code/docs/stream/FlowGraphDocTest.java#flow-graph-matvalue-cycle
|
||||
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ Finally, sending the emails:
|
|||
.. includecode:: ../code/docs/stream/IntegrationDocTest.java#send-emails
|
||||
|
||||
``mapAsync`` is applying the given function that is calling out to the external service to
|
||||
each of the elements as they pass through this processing step. The function returns a :class:`Future`
|
||||
each of the elements as they pass through this processing step. The function returns a :class:`CompletionStage`
|
||||
and the value of that future will be emitted downstreams. The number of Futures
|
||||
that shall run in parallel is given as the first argument to ``mapAsync``.
|
||||
These Futures may complete in any order, but the elements that are emitted
|
||||
|
|
@ -190,8 +190,8 @@ is not important and then we can use the more efficient ``mapAsyncUnordered``:
|
|||
|
||||
.. includecode:: ../code/docs/stream/IntegrationDocTest.java#external-service-mapAsyncUnordered
|
||||
|
||||
In the above example the services conveniently returned a :class:`Future` of the result.
|
||||
If that is not the case you need to wrap the call in a :class:`Future`. If the service call
|
||||
In the above example the services conveniently returned a :class:`CompletionStage` of the result.
|
||||
If that is not the case you need to wrap the call in a :class:`CompletionStage`. If the service call
|
||||
involves blocking you must also make sure that you run it on a dedicated execution context, to
|
||||
avoid starvation and disturbance of other tasks in the system.
|
||||
|
||||
|
|
@ -215,7 +215,7 @@ external service, you can use ``ask``:
|
|||
.. includecode:: ../code/docs/stream/IntegrationDocTest.java#save-tweets
|
||||
|
||||
Note that if the ``ask`` is not completed within the given timeout the stream is completed with failure.
|
||||
If that is not desired outcome you can use ``recover`` on the ``ask`` :class:`Future`.
|
||||
If that is not desired outcome you can use ``recover`` on the ``ask`` :class:`CompletionStage`.
|
||||
|
||||
Illustrating ordering and parallelism
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ Streaming TCP
|
|||
|
||||
Accepting connections: Echo Server
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
In order to implement a simple EchoServer we ``bind`` to a given address, which returns a ``Source<IncomingConnection, Future<ServerBinding>>``,
|
||||
In order to implement a simple EchoServer we ``bind`` to a given address, which returns a ``Source<IncomingConnection, CompletionStage<ServerBinding>>``,
|
||||
which will emit an :class:`IncomingConnection` element for each new connection that the Server should handle:
|
||||
|
||||
.. includecode:: ../code/docs/stream/io/StreamTcpDocTest.java#echo-server-simple-bind
|
||||
|
|
|
|||
|
|
@ -163,21 +163,21 @@ First, let's write such an element counter using ``Flow.of(Class)`` and ``Sink.f
|
|||
|
||||
First we prepare a reusable ``Flow`` that will change each incoming tweet into an integer of value ``1``. We'll use this in
|
||||
order to combine those with a ``Sink.fold`` that will sum all ``Integer`` elements of the stream and make its result available as
|
||||
a ``Future<Integer>``. Next we connect the ``tweets`` stream to ``count`` with ``via``. Finally we connect the Flow to the previously
|
||||
a ``CompletionStage<Integer>``. Next we connect the ``tweets`` stream to ``count`` with ``via``. Finally we connect the Flow to the previously
|
||||
prepared Sink using ``toMat``.
|
||||
|
||||
Remember those mysterious ``Mat`` type parameters on ``Source<Out, Mat>``, ``Flow<In, Out, Mat>`` and ``Sink<In, Mat>``?
|
||||
They represent the type of values these processing parts return when materialized. When you chain these together,
|
||||
you can explicitly combine their materialized values: in our example we used the ``Keep.right`` predefined function,
|
||||
which tells the implementation to only care about the materialized type of the stage currently appended to the right.
|
||||
The materialized type of ``sumSink`` is ``Future<Integer>`` and because of using ``Keep.right``, the resulting :class:`RunnableGraph`
|
||||
has also a type parameter of ``Future<Integer>``.
|
||||
The materialized type of ``sumSink`` is ``CompletionStage<Integer>`` and because of using ``Keep.right``, the resulting :class:`RunnableGraph`
|
||||
has also a type parameter of ``CompletionStage<Integer>``.
|
||||
|
||||
This step does *not* yet materialize the
|
||||
processing pipeline, it merely prepares the description of the Flow, which is now connected to a Sink, and therefore can
|
||||
be ``run()``, as indicated by its type: ``RunnableGraph<Future<Integer>>``. Next we call ``run()`` which uses the :class:`ActorMaterializer`
|
||||
be ``run()``, as indicated by its type: ``RunnableGraph<CompletionStage<Integer>>``. Next we call ``run()`` which uses the :class:`ActorMaterializer`
|
||||
to materialize and run the Flow. The value returned by calling ``run()`` on a ``RunnableGraph<T>`` is of type ``T``.
|
||||
In our case this type is ``Future<Integer>`` which, when completed, will contain the total length of our tweets stream.
|
||||
In our case this type is ``CompletionStage<Integer>`` which, when completed, will contain the total length of our tweets stream.
|
||||
In case of the stream failing, this future would complete with a Failure.
|
||||
|
||||
A :class:`RunnableGraph` may be reused
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ used for writing stream tests that use familiar :class:`TestProbe` from the
|
|||
:mod:`akka-testkit` API.
|
||||
|
||||
One of the more straightforward tests would be to materialize stream to a
|
||||
:class:`Future` and then use ``pipe`` pattern to pipe the result of that future
|
||||
:class:`CompletionStage` and then use ``PatternsCS.pipe`` pattern to pipe the result of that future
|
||||
to the probe.
|
||||
|
||||
.. includecode:: ../code/docs/stream/StreamTestKitDocTest.java#pipeto-testprobe
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue