=str fix sub-upstream cancellation in concatAll

- ActorProcessor terminated eagerly when ConcatAll had just taken up a
  new input stream but not yet received onSubscribe for it

- The ActorProcessor eagerly shuts itself down upon onError and that
  cannot be changed without completely reworking the Pump, so I opted
  for just tracking the outstanding substreamSubscribers that have not
  yet seen OnSubscribe and making them cancel properly when that arrives
  (possibly later).
This commit is contained in:
Roland Kuhn 2015-06-18 22:24:24 +02:00
parent 6e72271eb5
commit d462cdd1b4
16 changed files with 115 additions and 45 deletions

View file

@ -17,7 +17,7 @@ class ActorInterpreterLifecycleSpec extends AkkaSpec with InterpreterLifecycleSp
implicit val mat = ActorFlowMaterializer()
class Setup(ops: List[Stage[_, _]] = List(fusing.Map({ x: Any x }, stoppingDecider))) {
val up = TestPublisher.manualProbe[Int]
val up = TestPublisher.manualProbe[Int]()
val down = TestSubscriber.manualProbe[Int]
private val props = ActorInterpreter.props(mat.settings, ops, mat).withDispatcher("akka.test.stream-dispatcher")
val actor = system.actorOf(props)

View file

@ -22,7 +22,7 @@ class ActorInterpreterSpec extends AkkaSpec {
implicit val mat = ActorFlowMaterializer()
class Setup(ops: List[Stage[_, _]] = List(fusing.Map({ x: Any x }, stoppingDecider))) {
val up = TestPublisher.manualProbe[Int]
val up = TestPublisher.manualProbe[Int]()
val down = TestSubscriber.manualProbe[Int]
private val props = ActorInterpreter.props(mat.settings, ops, mat).withDispatcher("akka.test.stream-dispatcher")
val actor = system.actorOf(props)

View file

@ -71,6 +71,29 @@ class FlowConcatAllSpec extends AkkaSpec {
subUpstream.expectCancellation()
}
"on onError on master stream cancel the currently opening substream and signal error" in assertAllStagesStopped {
val publisher = TestPublisher.manualProbe[Source[Int, _]]()
val subscriber = TestSubscriber.manualProbe[Int]()
Source(publisher).flatten(FlattenStrategy.concat).to(Sink(subscriber)).run()
val upstream = publisher.expectSubscription()
val downstream = subscriber.expectSubscription()
downstream.request(1000)
val substreamPublisher = TestPublisher.manualProbe[Int](autoOnSubscribe = false)
val substreamFlow = Source(substreamPublisher)
upstream.expectRequest()
upstream.sendNext(substreamFlow)
val subUpstream = substreamPublisher.expectSubscription()
upstream.sendError(testException)
subUpstream.sendOnSubscribe()
subscriber.expectError(testException)
subUpstream.expectCancellation()
}
"on onError on open substream, cancel the master stream and signal error " in assertAllStagesStopped {
val publisher = TestPublisher.manualProbe[Source[Int, _]]()
val subscriber = TestSubscriber.manualProbe[Int]()
@ -112,6 +135,29 @@ class FlowConcatAllSpec extends AkkaSpec {
upstream.expectCancellation()
}
"on cancellation cancel the currently opening substream and the master stream" in assertAllStagesStopped {
val publisher = TestPublisher.manualProbe[Source[Int, _]]()
val subscriber = TestSubscriber.manualProbe[Int]()
Source(publisher).flatten(FlattenStrategy.concat).to(Sink(subscriber)).run()
val upstream = publisher.expectSubscription()
val downstream = subscriber.expectSubscription()
downstream.request(1000)
val substreamPublisher = TestPublisher.manualProbe[Int](autoOnSubscribe = false)
val substreamFlow = Source(substreamPublisher)
upstream.expectRequest()
upstream.sendNext(substreamFlow)
val subUpstream = substreamPublisher.expectSubscription()
downstream.cancel()
subUpstream.sendOnSubscribe()
subUpstream.expectCancellation()
upstream.expectCancellation()
}
"pass along early cancellation" in assertAllStagesStopped {
val up = TestPublisher.manualProbe[Source[Int, _]]()
val down = TestSubscriber.manualProbe[Int]()

View file

@ -258,8 +258,8 @@ class FlowGraphCompileSpec extends AkkaSpec {
"build with implicits and variance" in {
FlowGraph.closed() { implicit b
def appleSource = b.add(Source(TestPublisher.manualProbe[Apple]))
def fruitSource = b.add(Source(TestPublisher.manualProbe[Fruit]))
def appleSource = b.add(Source(TestPublisher.manualProbe[Apple]()))
def fruitSource = b.add(Source(TestPublisher.manualProbe[Fruit]()))
val outA = b add Sink(TestSubscriber.manualProbe[Fruit]())
val outB = b add Sink(TestSubscriber.manualProbe[Fruit]())
val merge = b add Merge[Fruit](11)

View file

@ -418,7 +418,7 @@ class FlowStageSpec extends AkkaSpec(ConfigFactory.parseString("akka.actor.debug
downstream.cancel()
onDownstreamFinishProbe.expectMsg("onDownstreamFinish")
val up = TestPublisher.manualProbe[Int]
val up = TestPublisher.manualProbe[Int]()
up.subscribe(s)
val upsub = up.expectSubscription()
upsub.expectCancellation()

View file

@ -570,7 +570,7 @@ class GraphFlexiMergeSpec extends AkkaSpec {
}
"propagate failure" in assertAllStagesStopped {
val publisher = TestPublisher.manualProbe[String]
val publisher = TestPublisher.manualProbe[String]()
val completionProbe = TestProbe()
val p = FlowGraph.closed(out) { implicit b
o
@ -587,7 +587,7 @@ class GraphFlexiMergeSpec extends AkkaSpec {
}
"emit failure" in assertAllStagesStopped {
val publisher = TestPublisher.manualProbe[String]
val publisher = TestPublisher.manualProbe[String]()
val completionProbe = TestProbe()
val p = FlowGraph.closed(out) { implicit b
o
@ -607,7 +607,7 @@ class GraphFlexiMergeSpec extends AkkaSpec {
}
"emit failure for user thrown exception" in assertAllStagesStopped {
val publisher = TestPublisher.manualProbe[String]
val publisher = TestPublisher.manualProbe[String]()
val completionProbe = TestProbe()
val p = FlowGraph.closed(out) { implicit b
o
@ -626,7 +626,7 @@ class GraphFlexiMergeSpec extends AkkaSpec {
}
"emit failure for user thrown exception in onComplete" in assertAllStagesStopped {
val publisher = TestPublisher.manualProbe[String]
val publisher = TestPublisher.manualProbe[String]()
val completionProbe = TestProbe()
val p = FlowGraph.closed(out) { implicit b
o
@ -670,7 +670,7 @@ class GraphFlexiMergeSpec extends AkkaSpec {
}
"support finish from onInput" in assertAllStagesStopped {
val publisher = TestPublisher.manualProbe[String]
val publisher = TestPublisher.manualProbe[String]()
val completionProbe = TestProbe()
val p = FlowGraph.closed(out) { implicit b
o

View file

@ -145,8 +145,8 @@ class GraphMergeSpec extends TwoStreamsSetup {
}
"pass along early cancellation" in assertAllStagesStopped {
val up1 = TestPublisher.manualProbe[Int]
val up2 = TestPublisher.manualProbe[Int]
val up1 = TestPublisher.manualProbe[Int]()
val up2 = TestPublisher.manualProbe[Int]()
val down = TestSubscriber.manualProbe[Int]()
val src1 = Source.subscriber[Int]

View file

@ -122,7 +122,7 @@ class SourceSpec extends AkkaSpec {
"Composite Source" must {
"merge from many inputs" in {
val probes = Seq.fill(5)(TestPublisher.manualProbe[Int])
val probes = Seq.fill(5)(TestPublisher.manualProbe[Int]())
val source = Source.subscriber[Int]
val out = TestSubscriber.manualProbe[Int]