#22808 Move CoupledTerminationFlow to Flow.fromSinkAndSourceCoupled
Also mention coupled variant in the uncoupled scaladoc
This commit is contained in:
parent
f2adb0a3fd
commit
c840bd6f37
7 changed files with 199 additions and 34 deletions
|
|
@ -1059,16 +1059,14 @@ Creates a `Flow` from a `Sink` and a `Source` where the Flow's input will be sen
|
||||||
and the `Flow` 's output will come from the Source.
|
and the `Flow` 's output will come from the Source.
|
||||||
|
|
||||||
Note that termination events, like completion and cancelation is not automatically propagated through to the "other-side"
|
Note that termination events, like completion and cancelation is not automatically propagated through to the "other-side"
|
||||||
of the such-composed Flow. Use `CoupledTerminationFlow` if you want to couple termination of both of the ends,
|
of the such-composed Flow. Use `Flow.fromSinkAndSourceCoupled` if you want to couple termination of both of the ends,
|
||||||
for example most useful in handling websocket connections.
|
for example most useful in handling websocket connections.
|
||||||
|
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
|
|
||||||
### CoupledTerminationFlow.fromSinkAndSource
|
### Flow.fromSinkAndSourceCoupled
|
||||||
|
|
||||||
Allows coupling termination (cancellation, completion, erroring) of Sinks and Sources while creating a Flow them them.
|
Allows coupling termination (cancellation, completion, erroring) of Sinks and Sources while creating a Flow them them.
|
||||||
Similar to `Flow.fromSinkAndSource` however that API does not connect the completion signals of the wrapped stages.
|
|
||||||
|
|
||||||
Similar to `Flow.fromSinkAndSource` however couples the termination of these two stages.
|
Similar to `Flow.fromSinkAndSource` however couples the termination of these two stages.
|
||||||
|
|
||||||
E.g. if the emitted `Flow` gets a cancellation, the `Source` of course is cancelled,
|
E.g. if the emitted `Flow` gets a cancellation, the `Source` of course is cancelled,
|
||||||
|
|
|
||||||
|
|
@ -1047,16 +1047,14 @@ Creates a `Flow` from a `Sink` and a `Source` where the Flow's input will be sen
|
||||||
and the `Flow` 's output will come from the Source.
|
and the `Flow` 's output will come from the Source.
|
||||||
|
|
||||||
Note that termination events, like completion and cancelation is not automatically propagated through to the "other-side"
|
Note that termination events, like completion and cancelation is not automatically propagated through to the "other-side"
|
||||||
of the such-composed Flow. Use `CoupledTerminationFlow` if you want to couple termination of both of the ends,
|
of the such-composed Flow. Use `Flow.fromSinkAndSourceCoupled` if you want to couple termination of both of the ends,
|
||||||
for example most useful in handling websocket connections.
|
for example most useful in handling websocket connections.
|
||||||
|
|
||||||
---------------------------------------------------------------
|
---------------------------------------------------------------
|
||||||
|
|
||||||
### CoupledTerminationFlow.fromSinkAndSource
|
### Flow.fromSinkAndSourceCoupled
|
||||||
|
|
||||||
Allows coupling termination (cancellation, completion, erroring) of Sinks and Sources while creating a Flow them them.
|
Allows coupling termination (cancellation, completion, erroring) of Sinks and Sources while creating a Flow them them.
|
||||||
Similar to `Flow.fromSinkAndSource` however that API does not connect the completion signals of the wrapped stages.
|
|
||||||
|
|
||||||
Similar to `Flow.fromSinkAndSource` however couples the termination of these two stages.
|
Similar to `Flow.fromSinkAndSource` however couples the termination of these two stages.
|
||||||
|
|
||||||
E.g. if the emitted `Flow` gets a cancellation, the `Source` of course is cancelled,
|
E.g. if the emitted `Flow` gets a cancellation, the `Source` of course is cancelled,
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,12 @@ package akka.stream.scaladsl
|
||||||
import akka.{ Done, NotUsed }
|
import akka.{ Done, NotUsed }
|
||||||
import akka.stream._
|
import akka.stream._
|
||||||
import akka.stream.testkit._
|
import akka.stream.testkit._
|
||||||
|
import akka.stream.testkit.scaladsl.{ TestSink, TestSource }
|
||||||
import akka.testkit.TestProbe
|
import akka.testkit.TestProbe
|
||||||
import org.reactivestreams.{ Publisher, Subscriber, Subscription }
|
import org.reactivestreams.{ Publisher, Subscriber, Subscription }
|
||||||
import org.scalatest.Assertion
|
import org.scalatest.Assertion
|
||||||
|
|
||||||
|
import scala.concurrent.Future
|
||||||
import scala.util.{ Failure, Success, Try }
|
import scala.util.{ Failure, Success, Try }
|
||||||
import scala.xml.Node
|
import scala.xml.Node
|
||||||
|
|
||||||
|
|
@ -72,7 +74,7 @@ class CoupledTerminationFlowSpec extends StreamSpec with ScriptedTest {
|
||||||
val (innerSink, innerSinkAssertion) = interpretInnerSink(innerSinkRule)
|
val (innerSink, innerSinkAssertion) = interpretInnerSink(innerSinkRule)
|
||||||
val (innerSource, innerSourceAssertion) = interpretInnerSource(innerSourceRule)
|
val (innerSource, innerSourceAssertion) = interpretInnerSource(innerSourceRule)
|
||||||
|
|
||||||
val flow = CoupledTerminationFlow.fromSinkAndSource(innerSink, innerSource)
|
val flow = Flow.fromSinkAndSourceCoupledMat(innerSink, innerSource)(Keep.none)
|
||||||
outerSource.via(flow).to(outerSink).run()
|
outerSource.via(flow).to(outerSink).run()
|
||||||
|
|
||||||
outerAssertions()
|
outerAssertions()
|
||||||
|
|
@ -83,9 +85,9 @@ class CoupledTerminationFlowSpec extends StreamSpec with ScriptedTest {
|
||||||
|
|
||||||
"completed out:Source => complete in:Sink" in {
|
"completed out:Source => complete in:Sink" in {
|
||||||
val probe = TestProbe()
|
val probe = TestProbe()
|
||||||
val f = CoupledTerminationFlow.fromSinkAndSource(
|
val f = Flow.fromSinkAndSourceCoupledMat(
|
||||||
Sink.onComplete(d ⇒ probe.ref ! "done"),
|
Sink.onComplete(d ⇒ probe.ref ! "done"),
|
||||||
Source.empty) // completes right away, should complete the sink as well
|
Source.empty)(Keep.none) // completes right away, should complete the sink as well
|
||||||
|
|
||||||
f.runWith(Source.maybe, Sink.ignore) // these do nothing.
|
f.runWith(Source.maybe, Sink.ignore) // these do nothing.
|
||||||
|
|
||||||
|
|
@ -94,7 +96,7 @@ class CoupledTerminationFlowSpec extends StreamSpec with ScriptedTest {
|
||||||
|
|
||||||
"cancel in:Sink => cancel out:Source" in {
|
"cancel in:Sink => cancel out:Source" in {
|
||||||
val probe = TestProbe()
|
val probe = TestProbe()
|
||||||
val f = CoupledTerminationFlow.fromSinkAndSource(
|
val f = Flow.fromSinkAndSourceCoupledMat(
|
||||||
Sink.cancelled,
|
Sink.cancelled,
|
||||||
Source.fromPublisher(new Publisher[String] {
|
Source.fromPublisher(new Publisher[String] {
|
||||||
override def subscribe(subscriber: Subscriber[_ >: String]): Unit = {
|
override def subscribe(subscriber: Subscriber[_ >: String]): Unit = {
|
||||||
|
|
@ -104,7 +106,7 @@ class CoupledTerminationFlowSpec extends StreamSpec with ScriptedTest {
|
||||||
override def request(l: Long): Unit = () // do nothing
|
override def request(l: Long): Unit = () // do nothing
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})) // completes right away, should complete the sink as well
|
}))(Keep.none) // completes right away, should complete the sink as well
|
||||||
|
|
||||||
f.runWith(Source.maybe, Sink.ignore) // these do nothing.
|
f.runWith(Source.maybe, Sink.ignore) // these do nothing.
|
||||||
|
|
||||||
|
|
@ -113,15 +115,27 @@ class CoupledTerminationFlowSpec extends StreamSpec with ScriptedTest {
|
||||||
|
|
||||||
"error wrapped Sink when wrapped Source errors " in {
|
"error wrapped Sink when wrapped Source errors " in {
|
||||||
val probe = TestProbe()
|
val probe = TestProbe()
|
||||||
val f = CoupledTerminationFlow.fromSinkAndSource(
|
val f = Flow.fromSinkAndSourceCoupledMat(
|
||||||
Sink.onComplete(e ⇒ probe.ref ! e.failed.get.getMessage),
|
Sink.onComplete(e ⇒ probe.ref ! e.failed.get.getMessage),
|
||||||
Source.failed(new Exception("BOOM!"))) // completes right away, should complete the sink as well
|
Source.failed(new Exception("BOOM!")))(Keep.none) // completes right away, should complete the sink as well
|
||||||
|
|
||||||
f.runWith(Source.maybe, Sink.ignore) // these do nothing.
|
f.runWith(Source.maybe, Sink.ignore) // these do nothing.
|
||||||
|
|
||||||
probe.expectMsg("BOOM!")
|
probe.expectMsg("BOOM!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"support usage with Graphs" in {
|
||||||
|
val source: Graph[SourceShape[Int], TestPublisher.Probe[Int]] = TestSource.probe[Int]
|
||||||
|
val sink: Graph[SinkShape[Any], Future[Done]] = Sink.ignore
|
||||||
|
|
||||||
|
val flow = Flow.fromSinkAndSourceCoupledMat(sink, source)(Keep.right)
|
||||||
|
|
||||||
|
val (source1, source2) = TestSource.probe[Int].viaMat(flow)(Keep.both).toMat(Sink.ignore)(Keep.left).run
|
||||||
|
|
||||||
|
source1.sendComplete()
|
||||||
|
source2.expectCancellation()
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def interpretOuter(rule: String): (Source[String, NotUsed], Sink[String, NotUsed], () ⇒ Any) = {
|
def interpretOuter(rule: String): (Source[String, NotUsed], Sink[String, NotUsed], () ⇒ Any) = {
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,7 @@ object CoupledTerminationFlow {
|
||||||
*
|
*
|
||||||
* The order in which the `in` and `out` sides receive their respective completion signals is not defined, do not rely on its ordering.
|
* The order in which the `in` and `out` sides receive their respective completion signals is not defined, do not rely on its ordering.
|
||||||
*/
|
*/
|
||||||
|
@deprecated("Use `Flow.fromSinkAndSourceCoupledMat(..., ..., Keep.both())` instead", "2.5.2")
|
||||||
def fromSinkAndSource[I, O, M1, M2](in: Sink[I, M1], out: Source[O, M2]): Flow[I, O, (M1, M2)] =
|
def fromSinkAndSource[I, O, M1, M2](in: Sink[I, M1], out: Source[O, M2]): Flow[I, O, (M1, M2)] =
|
||||||
akka.stream.scaladsl.CoupledTerminationFlow.fromSinkAndSource(in.asScala, out.asScala).asJava
|
akka.stream.scaladsl.Flow.fromSinkAndSourceCoupledMat(in, out)(akka.stream.scaladsl.Keep.both).asJava
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,18 +55,98 @@ object Flow {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to create `Flow` from a `Sink`and a `Source`.
|
* Creates a `Flow` from a `Sink` and a `Source` where the Flow's input
|
||||||
|
* will be sent to the Sink and the Flow's output will come from the Source.
|
||||||
|
*
|
||||||
|
* The completion of the Sink and Source sides of a Flow constructed using
|
||||||
|
* this method are independent. So if the Sink receives a completion signal,
|
||||||
|
* the Source side will remain unaware of that. If you are looking to couple
|
||||||
|
* the termination signals of the two sides use `Flow.fromSinkAndSourceCoupled` instead.
|
||||||
*/
|
*/
|
||||||
def fromSinkAndSource[I, O](sink: Graph[SinkShape[I], _], source: Graph[SourceShape[O], _]): Flow[I, O, NotUsed] =
|
def fromSinkAndSource[I, O](sink: Graph[SinkShape[I], _], source: Graph[SourceShape[O], _]): Flow[I, O, NotUsed] =
|
||||||
new Flow(scaladsl.Flow.fromSinkAndSourceMat(sink, source)(scaladsl.Keep.none))
|
new Flow(scaladsl.Flow.fromSinkAndSourceMat(sink, source)(scaladsl.Keep.none))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to create `Flow` from a `Sink`and a `Source`.
|
* Creates a `Flow` from a `Sink` and a `Source` where the Flow's input
|
||||||
|
* will be sent to the Sink and the Flow's output will come from the Source.
|
||||||
|
*
|
||||||
|
* The completion of the Sink and Source sides of a Flow constructed using
|
||||||
|
* this method are independent. So if the Sink receives a completion signal,
|
||||||
|
* the Source side will remain unaware of that. If you are looking to couple
|
||||||
|
* the termination signals of the two sides use `Flow.fromSinkAndSourceCoupledMat` instead.
|
||||||
|
*
|
||||||
|
* The `combine` function is used to compose the materialized values of the `sink` and `source`
|
||||||
|
* into the materialized value of the resulting [[Flow]].
|
||||||
*/
|
*/
|
||||||
def fromSinkAndSourceMat[I, O, M1, M2, M](
|
def fromSinkAndSourceMat[I, O, M1, M2, M](
|
||||||
sink: Graph[SinkShape[I], M1], source: Graph[SourceShape[O], M2],
|
sink: Graph[SinkShape[I], M1], source: Graph[SourceShape[O], M2],
|
||||||
combine: function.Function2[M1, M2, M]): Flow[I, O, M] =
|
combine: function.Function2[M1, M2, M]): Flow[I, O, M] =
|
||||||
new Flow(scaladsl.Flow.fromSinkAndSourceMat(sink, source)(combinerToScala(combine)))
|
new Flow(scaladsl.Flow.fromSinkAndSourceMat(sink, source)(combinerToScala(combine)))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows coupling termination (cancellation, completion, erroring) of Sinks and Sources while creating a Flow from them.
|
||||||
|
* Similar to [[Flow.fromSinkAndSource]] however couples the termination of these two stages.
|
||||||
|
*
|
||||||
|
* E.g. if the emitted [[Flow]] gets a cancellation, the [[Source]] of course is cancelled,
|
||||||
|
* however the Sink will also be completed. The table below illustrates the effects in detail:
|
||||||
|
*
|
||||||
|
* <table>
|
||||||
|
* <tr>
|
||||||
|
* <th>Returned Flow</th>
|
||||||
|
* <th>Sink (<code>in</code>)</th>
|
||||||
|
* <th>Source (<code>out</code>)</th>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><i>cause:</i> upstream (sink-side) receives completion</td>
|
||||||
|
* <td><i>effect:</i> receives completion</td>
|
||||||
|
* <td><i>effect:</i> receives cancel</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><i>cause:</i> upstream (sink-side) receives error</td>
|
||||||
|
* <td><i>effect:</i> receives error</td>
|
||||||
|
* <td><i>effect:</i> receives cancel</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><i>cause:</i> downstream (source-side) receives cancel</td>
|
||||||
|
* <td><i>effect:</i> completes</td>
|
||||||
|
* <td><i>effect:</i> receives cancel</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><i>effect:</i> cancels upstream, completes downstream</td>
|
||||||
|
* <td><i>effect:</i> completes</td>
|
||||||
|
* <td><i>cause:</i> signals complete</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><i>effect:</i> cancels upstream, errors downstream</td>
|
||||||
|
* <td><i>effect:</i> receives error</td>
|
||||||
|
* <td><i>cause:</i> signals error or throws</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><i>effect:</i> cancels upstream, completes downstream</td>
|
||||||
|
* <td><i>cause:</i> cancels</td>
|
||||||
|
* <td><i>effect:</i> receives cancel</td>
|
||||||
|
* </tr>
|
||||||
|
* </table>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
def fromSinkAndSourceCoupled[I, O](sink: Graph[SinkShape[I], _], source: Graph[SourceShape[O], _]): Flow[I, O, NotUsed] =
|
||||||
|
new Flow(scaladsl.Flow.fromSinkAndSourceCoupled(sink, source))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows coupling termination (cancellation, completion, erroring) of Sinks and Sources while creating a Flow from them.
|
||||||
|
* Similar to [[Flow.fromSinkAndSource]] however couples the termination of these two stages.
|
||||||
|
*
|
||||||
|
* E.g. if the emitted [[Flow]] gets a cancellation, the [[Source]] of course is cancelled,
|
||||||
|
* however the Sink will also be completed. The table on [[Flow.fromSinkAndSourceCoupled]]
|
||||||
|
* illustrates the effects in detail.
|
||||||
|
*
|
||||||
|
* The `combine` function is used to compose the materialized values of the `sink` and `source`
|
||||||
|
* into the materialized value of the resulting [[Flow]].
|
||||||
|
*/
|
||||||
|
def fromSinkAndSourceCoupledMat[I, O, M1, M2, M](
|
||||||
|
sink: Graph[SinkShape[I], M1], source: Graph[SourceShape[O], M2],
|
||||||
|
combine: function.Function2[M1, M2, M]): Flow[I, O, M] =
|
||||||
|
new Flow(scaladsl.Flow.fromSinkAndSourceCoupledMat(sink, source)(combinerToScala(combine)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Create a `Flow` which can process elements of type `T`. */
|
/** Create a `Flow` which can process elements of type `T`. */
|
||||||
|
|
|
||||||
|
|
@ -59,15 +59,9 @@ object CoupledTerminationFlow {
|
||||||
*
|
*
|
||||||
* The order in which the `in` and `out` sides receive their respective completion signals is not defined, do not rely on its ordering.
|
* The order in which the `in` and `out` sides receive their respective completion signals is not defined, do not rely on its ordering.
|
||||||
*/
|
*/
|
||||||
|
@deprecated("Use `Flow.fromSinkAndSourceCoupledMat(..., ...)(Keep.both)` instead", "2.5.2")
|
||||||
def fromSinkAndSource[I, O, M1, M2](in: Sink[I, M1], out: Source[O, M2]): Flow[I, O, (M1, M2)] =
|
def fromSinkAndSource[I, O, M1, M2](in: Sink[I, M1], out: Source[O, M2]): Flow[I, O, (M1, M2)] =
|
||||||
// format: OFF
|
Flow.fromSinkAndSourceCoupledMat(in, out)(Keep.both)
|
||||||
Flow.fromGraph(GraphDSL.create(in, out)(Keep.both) { implicit b => (i, o) =>
|
|
||||||
import GraphDSL.Implicits._
|
|
||||||
val bidi = b.add(new CoupledTerminationBidi[I, O])
|
|
||||||
/* bidi.in1 ~> */ bidi.out1 ~> i; o ~> bidi.in2 /* ~> bidi.out2 */
|
|
||||||
FlowShape(bidi.in1, bidi.out2)
|
|
||||||
})
|
|
||||||
// format: ON
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -315,6 +315,11 @@ object Flow {
|
||||||
/**
|
/**
|
||||||
* Creates a `Flow` from a `Sink` and a `Source` where the Flow's input
|
* Creates a `Flow` from a `Sink` and a `Source` where the Flow's input
|
||||||
* will be sent to the Sink and the Flow's output will come from the Source.
|
* will be sent to the Sink and the Flow's output will come from the Source.
|
||||||
|
*
|
||||||
|
* The completion of the Sink and Source sides of a Flow constructed using
|
||||||
|
* this method are independent. So if the Sink receives a completion signal,
|
||||||
|
* the Source side will remain unaware of that. If you are looking to couple
|
||||||
|
* the termination signals of the two sides use `Flow.fromSinkAndSourceCoupled` instead.
|
||||||
*/
|
*/
|
||||||
def fromSinkAndSource[I, O](sink: Graph[SinkShape[I], _], source: Graph[SourceShape[O], _]): Flow[I, O, NotUsed] =
|
def fromSinkAndSource[I, O](sink: Graph[SinkShape[I], _], source: Graph[SourceShape[O], _]): Flow[I, O, NotUsed] =
|
||||||
fromSinkAndSourceMat(sink, source)(Keep.none)
|
fromSinkAndSourceMat(sink, source)(Keep.none)
|
||||||
|
|
@ -323,11 +328,86 @@ object Flow {
|
||||||
* Creates a `Flow` from a `Sink` and a `Source` where the Flow's input
|
* Creates a `Flow` from a `Sink` and a `Source` where the Flow's input
|
||||||
* will be sent to the Sink and the Flow's output will come from the Source.
|
* will be sent to the Sink and the Flow's output will come from the Source.
|
||||||
*
|
*
|
||||||
|
* The completion of the Sink and Source sides of a Flow constructed using
|
||||||
|
* this method are independent. So if the Sink receives a completion signal,
|
||||||
|
* the Source side will remain unaware of that. If you are looking to couple
|
||||||
|
* the termination signals of the two sides use `Flow.fromSinkAndSourceCoupledMat` instead.
|
||||||
|
*
|
||||||
* The `combine` function is used to compose the materialized values of the `sink` and `source`
|
* The `combine` function is used to compose the materialized values of the `sink` and `source`
|
||||||
* into the materialized value of the resulting [[Flow]].
|
* into the materialized value of the resulting [[Flow]].
|
||||||
*/
|
*/
|
||||||
def fromSinkAndSourceMat[I, O, M1, M2, M](sink: Graph[SinkShape[I], M1], source: Graph[SourceShape[O], M2])(combine: (M1, M2) ⇒ M): Flow[I, O, M] =
|
def fromSinkAndSourceMat[I, O, M1, M2, M](sink: Graph[SinkShape[I], M1], source: Graph[SourceShape[O], M2])(combine: (M1, M2) ⇒ M): Flow[I, O, M] =
|
||||||
fromGraph(GraphDSL.create(sink, source)(combine) { implicit b ⇒ (in, out) ⇒ FlowShape(in.in, out.out) })
|
fromGraph(GraphDSL.create(sink, source)(combine) { implicit b ⇒ (in, out) ⇒ FlowShape(in.in, out.out) })
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows coupling termination (cancellation, completion, erroring) of Sinks and Sources while creating a Flow from them.
|
||||||
|
* Similar to [[Flow.fromSinkAndSource]] however couples the termination of these two stages.
|
||||||
|
*
|
||||||
|
* E.g. if the emitted [[Flow]] gets a cancellation, the [[Source]] of course is cancelled,
|
||||||
|
* however the Sink will also be completed. The table below illustrates the effects in detail:
|
||||||
|
*
|
||||||
|
* <table>
|
||||||
|
* <tr>
|
||||||
|
* <th>Returned Flow</th>
|
||||||
|
* <th>Sink (<code>in</code>)</th>
|
||||||
|
* <th>Source (<code>out</code>)</th>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><i>cause:</i> upstream (sink-side) receives completion</td>
|
||||||
|
* <td><i>effect:</i> receives completion</td>
|
||||||
|
* <td><i>effect:</i> receives cancel</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><i>cause:</i> upstream (sink-side) receives error</td>
|
||||||
|
* <td><i>effect:</i> receives error</td>
|
||||||
|
* <td><i>effect:</i> receives cancel</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><i>cause:</i> downstream (source-side) receives cancel</td>
|
||||||
|
* <td><i>effect:</i> completes</td>
|
||||||
|
* <td><i>effect:</i> receives cancel</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><i>effect:</i> cancels upstream, completes downstream</td>
|
||||||
|
* <td><i>effect:</i> completes</td>
|
||||||
|
* <td><i>cause:</i> signals complete</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><i>effect:</i> cancels upstream, errors downstream</td>
|
||||||
|
* <td><i>effect:</i> receives error</td>
|
||||||
|
* <td><i>cause:</i> signals error or throws</td>
|
||||||
|
* </tr>
|
||||||
|
* <tr>
|
||||||
|
* <td><i>effect:</i> cancels upstream, completes downstream</td>
|
||||||
|
* <td><i>cause:</i> cancels</td>
|
||||||
|
* <td><i>effect:</i> receives cancel</td>
|
||||||
|
* </tr>
|
||||||
|
* </table>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
def fromSinkAndSourceCoupled[I, O](sink: Graph[SinkShape[I], _], source: Graph[SourceShape[O], _]): Flow[I, O, NotUsed] =
|
||||||
|
fromSinkAndSourceCoupledMat(sink, source)(Keep.none)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows coupling termination (cancellation, completion, erroring) of Sinks and Sources while creating a Flow from them.
|
||||||
|
* Similar to [[Flow.fromSinkAndSource]] however couples the termination of these two stages.
|
||||||
|
*
|
||||||
|
* E.g. if the emitted [[Flow]] gets a cancellation, the [[Source]] of course is cancelled,
|
||||||
|
* however the Sink will also be completed. The table on [[Flow.fromSinkAndSourceCoupled]]
|
||||||
|
* illustrates the effects in detail.
|
||||||
|
*
|
||||||
|
* The `combine` function is used to compose the materialized values of the `sink` and `source`
|
||||||
|
* into the materialized value of the resulting [[Flow]].
|
||||||
|
*/
|
||||||
|
def fromSinkAndSourceCoupledMat[I, O, M1, M2, M](sink: Graph[SinkShape[I], M1], source: Graph[SourceShape[O], M2])(combine: (M1, M2) ⇒ M): Flow[I, O, M] =
|
||||||
|
// format: OFF
|
||||||
|
Flow.fromGraph(GraphDSL.create(sink, source)(combine) { implicit b => (i, o) =>
|
||||||
|
import GraphDSL.Implicits._
|
||||||
|
val bidi = b.add(new CoupledTerminationBidi[I, O])
|
||||||
|
/* bidi.in1 ~> */ bidi.out1 ~> i; o ~> bidi.in2 /* ~> bidi.out2 */
|
||||||
|
FlowShape(bidi.in1, bidi.out2)
|
||||||
|
})
|
||||||
|
// format: ON
|
||||||
}
|
}
|
||||||
|
|
||||||
object RunnableGraph {
|
object RunnableGraph {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue