fail fast in mapAsync for completed failed future, #21318 (#21322)

* fail fast in mapAsync for completed failed future, #21318

* the callback was not run until todo == parallelism or the sync
  event limit was reached, and that can be a problem if upstream
  stages are slow (noticed this for a blocking Kafka producer stage)

* skip callback for completed futures

* fix callback allocation
This commit is contained in:
Patrik Nordwall 2016-08-30 19:30:08 +02:00 committed by GitHub
parent e20d6f5f36
commit a95b2d6746
4 changed files with 100 additions and 43 deletions

View file

@ -48,10 +48,12 @@ class FlowMapAsyncSpec extends StreamSpec {
"produce future elements in order" in {
val c = TestSubscriber.manualProbe[Int]()
implicit val ec = system.dispatcher
val p = Source(1 to 50).mapAsync(4)(n Future {
Thread.sleep(ThreadLocalRandom.current().nextInt(1, 10))
n
}).to(Sink.fromSubscriber(c)).run()
val p = Source(1 to 50).mapAsync(4)(n
if (n % 3 == 0) Future.successful(n)
else Future {
Thread.sleep(ThreadLocalRandom.current().nextInt(1, 10))
n
}).to(Sink.fromSubscriber(c)).run()
val sub = c.expectSubscription()
sub.request(1000)
for (n 1 to 50) c.expectNext(n)
@ -99,6 +101,27 @@ class FlowMapAsyncSpec extends StreamSpec {
latch.countDown()
}
"signal future failure asap" in assertAllStagesStopped {
val latch = TestLatch(1)
val done = Source(1 to 5)
.map { n
if (n == 1) n
else {
// slow upstream should not block the error
Await.ready(latch, 10.seconds)
n
}
}
.mapAsync(4) { n
if (n == 1) Future.failed(new RuntimeException("err1") with NoStackTrace)
else Future.successful(n)
}.runWith(Sink.ignore)
intercept[RuntimeException] {
Await.result(done, remainingOrDefault)
}.getMessage should be("err1")
latch.countDown()
}
"signal error from mapAsync" in assertAllStagesStopped {
val latch = TestLatch(1)
val c = TestSubscriber.manualProbe[Int]()