Implements actorRef source variant with backpressure #17610 (#26633)

* Implements actorRef source variant with backpressure #17610

* Small improvements to documentation and source #17610

* Small improvements to test #17610

* Small improvements to implementation and tests #17610

* Adds API for akka-typed #17610

* Adds ack sender and java api for typed #17610
This commit is contained in:
Nicolas Vollmar 2019-05-20 12:19:44 +02:00 committed by Patrik Nordwall
parent a9f4f2dd96
commit f37f41574d
14 changed files with 472 additions and 6 deletions

View file

@ -0,0 +1,24 @@
# actorRefWithAck
Materialize an @java[`ActorRef<T>`]@scala[`ActorRef[T]`]; sending messages to it will emit them on the stream. The source acknowledges reception after emitting a message, to provide back pressure from the source.
@ref[Source operators](../index.md#source-operators)
@@@ div { .group-scala }
## Signature
@@signature [Source.scala](/akka-stream-typed/src/main/scala/akka/stream/typed/scaladsl/ActorSource.scala) { #actorRefWithAck }
@@@
## Description
Materialize an @java[`ActorRef<T>`]@scala[`ActorRef[T]`], sending messages to it will emit them on the stream. The actor responds with the provided ack message
once the element could be emitted alowing for backpressure from the source. Sending another message before the previous one has been acknowledged will fail the stream.
@@@div { .callout }
**emits** when there is demand and there are messages in the buffer or a message is sent to the `ActorRef`
**completes** when the `ActorRef` is sent `akka.actor.Status.Success`
@@@

View file

@ -0,0 +1,33 @@
# actorRefWithAck
Materialize an `ActorRef`; sending messages to it will emit them on the stream. The source acknowledges reception after emitting a message, to provide back pressure from the source.
@ref[Source operators](../index.md#source-operators)
@@@ div { .group-scala }
## Signature
@@signature [Source.scala](/akka-stream/src/main/scala/akka/stream/scaladsl/Source.scala) { #actorRefWithAck }
@@@
## Description
Materialize an `ActorRef`, sending messages to it will emit them on the stream. The actor responds with the provided ack message
once the element could be emitted alowing for backpressure from the source. Sending another message before the previous one has been acknowledged will fail the stream.
@@@div { .callout }
**emits** when there is demand and there are messages in the buffer or a message is sent to the `ActorRef`
**completes** when the `ActorRef` is sent `akka.actor.Status.Success`
@@@
## Examples
Scala
: @@snip [actorRef.scala](/akka-docs/src/test/scala/docs/stream/operators/SourceOperators.scala) { #actorRefWithAck }
Java
: @@snip [actorRef.java](/akka-docs/src/test/java/jdocs/stream/operators/SourceDocExamples.java) { #actor-ref-imports #actor-ref-with-ack }

View file

@ -8,6 +8,8 @@ These built-in sources are available from @scala[`akka.stream.scaladsl.Source`]
| |Operator|Description|
|--|--|--|
|Source|<a name="actorref"></a>@ref[actorRef](Source/actorRef.md)|Materialize an `ActorRef`; sending messages to it will emit them on the stream.|
|Source|<a name="actorrefwithack"></a>@ref[actorRefWithAck](Source/actorRefWithAck.md)|Materialize an `ActorRef`; sending messages to it will emit them on the stream. The source acknowledges reception after emitting a message, to provide back pressure from the source.|
|ActorSource|<a name="actorrefwithack"></a>@ref[actorRefWithAck](ActorSource/actorRefWithAck.md)|Materialize an @java[`ActorRef<T>`]@scala[`ActorRef[T]`]; sending messages to it will emit them on the stream. The source acknowledges reception after emitting a message, to provide back pressure from the source.|
|Source|<a name="assourcewithcontext"></a>@ref[asSourceWithContext](Source/asSourceWithContext.md)|Turns a Source into a SourceWithContext which can propagate a context per element along a stream.|
|Source|<a name="assubscriber"></a>@ref[asSubscriber](Source/asSubscriber.md)|Integration with Reactive Streams, materializes into a `org.reactivestreams.Subscriber`.|
|Source|<a name="combine"></a>@ref[combine](Source/combine.md)|Combine several sources, using a given strategy such as merge or concat, into one source.|
@ -310,6 +312,7 @@ For more background see the @ref[Error Handling in Streams](../stream-error.md)
* [lazilyAsync](Source/lazilyAsync.md)
* [asSubscriber](Source/asSubscriber.md)
* [actorRef](Source/actorRef.md)
* [actorRefWithAck](Source/actorRefWithAck.md)
* [zipN](Source/zipN.md)
* [zipWithN](Source/zipWithN.md)
* [queue](Source/queue.md)
@ -433,6 +436,7 @@ For more background see the @ref[Error Handling in Streams](../stream-error.md)
* [withBackoff](RestartFlow/withBackoff.md)
* [onFailuresWithBackoff](RestartFlow/onFailuresWithBackoff.md)
* [withBackoff](RestartSink/withBackoff.md)
* [actorRefWithAck](ActorSource/actorRefWithAck.md)
* [ask](ActorFlow/ask.md)
* [actorRef](ActorSink/actorRef.md)

View file

@ -8,8 +8,9 @@ package jdocs.stream.operators;
// #range-imports
import akka.NotUsed;
import akka.actor.ActorSystem;
import akka.actor.testkit.typed.javadsl.ManualTime;
import akka.actor.testkit.typed.javadsl.TestKitJunitResource;
import akka.stream.ActorMaterializer;
import akka.stream.CompletionStrategy;
import akka.stream.Materializer;
import akka.stream.javadsl.Source;
// #range-imports
@ -18,7 +19,9 @@ import akka.stream.javadsl.Source;
import akka.actor.ActorRef;
import akka.actor.Status.Success;
import akka.stream.OverflowStrategy;
import akka.stream.CompletionStrategy;
import akka.stream.javadsl.Sink;
import akka.testkit.TestProbe;
// #actor-ref-imports
import java.util.Arrays;
@ -27,6 +30,8 @@ import java.util.Arrays;
public class SourceDocExamples {
public static final TestKitJunitResource testKit = new TestKitJunitResource(ManualTime.config());
public static void fromExample() {
// #source-from-example
final ActorSystem system = ActorSystem.create("SourceFromExample");
@ -85,4 +90,24 @@ public class SourceDocExamples {
actorRef.tell(new Success(CompletionStrategy.draining()), ActorRef.noSender());
// #actor-ref
}
static void actorRefWithAck() {
final TestProbe probe = null;
// #actor-ref-with-ack
final ActorSystem system = ActorSystem.create();
final Materializer materializer = ActorMaterializer.create(system);
Source<Object, ActorRef> source = Source.actorRefWithAck("ack");
ActorRef actorRef = source.to(Sink.foreach(System.out::println)).run(materializer);
probe.send(actorRef, "hello");
probe.expectMsg("ack");
probe.send(actorRef, "hello");
probe.expectMsg("ack");
// The stream completes successfully with the following message
actorRef.tell(new Success(CompletionStrategy.draining()), ActorRef.noSender());
// #actor-ref-with-ack
}
}

View file

@ -6,6 +6,7 @@ package docs.stream.operators
import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import akka.testkit.TestProbe
object SourceOperators {
@ -35,6 +36,7 @@ object SourceOperators {
import akka.actor.Status.Success
import akka.actor.ActorRef
import akka.stream.OverflowStrategy
import akka.stream.CompletionStrategy
import akka.stream.scaladsl._
implicit val system: ActorSystem = ActorSystem()
@ -48,7 +50,32 @@ object SourceOperators {
actorRef ! "hello"
// The stream completes successfully with the following message
actorRef ! Success("completes stream")
actorRef ! Success(CompletionStrategy.immediately)
//#actorRef
}
def actorRefWithAck(): Unit = {
//#actorRefWithAck
import akka.actor.Status.Success
import akka.actor.ActorRef
import akka.stream.CompletionStrategy
import akka.stream.scaladsl._
implicit val system: ActorSystem = ActorSystem()
implicit val materializer: ActorMaterializer = ActorMaterializer()
val probe = TestProbe()
val source: Source[Any, ActorRef] = Source.actorRefWithAck[Any]("ack")
val actorRef: ActorRef = source.to(Sink.foreach(println)).run()
probe.send(actorRef, "hello")
probe.expectMsg("ack")
probe.send(actorRef, "hello")
probe.expectMsg("ack")
// The stream completes successfully with the following message
actorRef ! Success(CompletionStrategy.immediately)
//#actorRefWithAck
}
}