* it was noticed in Source.fromIterator depending on where the iterator throwed exception * fromIterator, as many other things, is implemented with statefulMapConcat * supervision was only used for exceptions in onPush and not in onPull, added it there also
This commit is contained in:
parent
e73bc64ade
commit
63ceb52bbd
3 changed files with 53 additions and 16 deletions
|
|
@ -39,9 +39,7 @@ class FlowIterableSpec extends AbstractFlowIteratorSpec {
|
||||||
sub.request(1)
|
sub.request(1)
|
||||||
c.expectNext(1)
|
c.expectNext(1)
|
||||||
c.expectNoMsg(100.millis)
|
c.expectNoMsg(100.millis)
|
||||||
EventFilter[IllegalStateException](message = "not two", occurrences = 1).intercept {
|
|
||||||
sub.request(2)
|
sub.request(2)
|
||||||
}
|
|
||||||
c.expectError().getMessage should be("not two")
|
c.expectError().getMessage should be("not two")
|
||||||
sub.request(2)
|
sub.request(2)
|
||||||
c.expectNoMsg(100.millis)
|
c.expectNoMsg(100.millis)
|
||||||
|
|
|
||||||
|
|
@ -6,9 +6,10 @@ package akka.stream.scaladsl
|
||||||
|
|
||||||
import akka.testkit.DefaultTimeout
|
import akka.testkit.DefaultTimeout
|
||||||
import org.scalatest.time.{ Millis, Span }
|
import org.scalatest.time.{ Millis, Span }
|
||||||
|
|
||||||
import scala.concurrent.{ Await, Future }
|
import scala.concurrent.{ Await, Future }
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
import akka.stream.testkit.Utils.TE
|
||||||
//#imports
|
//#imports
|
||||||
import akka.stream._
|
import akka.stream._
|
||||||
|
|
||||||
|
|
@ -266,6 +267,34 @@ class SourceSpec extends StreamSpec with DefaultTimeout {
|
||||||
.runWith(Sink.head)
|
.runWith(Sink.head)
|
||||||
.futureValue should ===(immutable.Seq(false, true, false, true, false, true, false, true, false, true))
|
.futureValue should ===(immutable.Seq(false, true, false, true, false, true, false, true, false, true))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"fail stream when iterator throws" in {
|
||||||
|
Source
|
||||||
|
.fromIterator(() ⇒ (1 to 1000).toIterator.map(k ⇒ if (k < 10) k else throw TE("a")))
|
||||||
|
.runWith(Sink.ignore)
|
||||||
|
.failed.futureValue.getClass should ===(classOf[TE])
|
||||||
|
|
||||||
|
Source
|
||||||
|
.fromIterator(() ⇒ (1 to 1000).toIterator.map(_ ⇒ throw TE("b")))
|
||||||
|
.runWith(Sink.ignore)
|
||||||
|
.failed.futureValue.getClass should ===(classOf[TE])
|
||||||
|
}
|
||||||
|
|
||||||
|
"use decider when iterator throws" in {
|
||||||
|
Source
|
||||||
|
.fromIterator(() ⇒ (1 to 5).toIterator.map(k ⇒ if (k != 3) k else throw TE("a")))
|
||||||
|
.withAttributes(ActorAttributes.supervisionStrategy(Supervision.restartingDecider))
|
||||||
|
.grouped(10)
|
||||||
|
.runWith(Sink.head)
|
||||||
|
.futureValue should ===(List(1, 2))
|
||||||
|
|
||||||
|
Source
|
||||||
|
.fromIterator(() ⇒ (1 to 5).toIterator.map(_ ⇒ throw TE("b")))
|
||||||
|
.withAttributes(ActorAttributes.supervisionStrategy(Supervision.restartingDecider))
|
||||||
|
.grouped(10)
|
||||||
|
.runWith(Sink.headOption)
|
||||||
|
.futureValue should ===(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
"ZipN Source" must {
|
"ZipN Source" must {
|
||||||
|
|
|
||||||
|
|
@ -18,16 +18,17 @@ import akka.stream.impl.{ ReactiveStreamsCompliance, Buffer ⇒ BufferImpl }
|
||||||
import akka.stream.scaladsl.{ Flow, Keep, Source }
|
import akka.stream.scaladsl.{ Flow, Keep, Source }
|
||||||
import akka.stream.stage._
|
import akka.stream.stage._
|
||||||
import akka.stream.{ Supervision, _ }
|
import akka.stream.{ Supervision, _ }
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.collection.immutable
|
import scala.collection.immutable
|
||||||
import scala.collection.immutable.VectorBuilder
|
import scala.collection.immutable.VectorBuilder
|
||||||
import scala.concurrent.{ Future, Promise }
|
import scala.concurrent.{ Future, Promise }
|
||||||
import scala.util.control.{ NoStackTrace, NonFatal }
|
import scala.util.control.{ NoStackTrace, NonFatal }
|
||||||
import scala.util.{ Failure, Success, Try }
|
import scala.util.{ Failure, Success, Try }
|
||||||
import akka.stream.ActorAttributes.SupervisionStrategy
|
|
||||||
|
|
||||||
|
import akka.stream.ActorAttributes.SupervisionStrategy
|
||||||
import scala.concurrent.duration.{ FiniteDuration, _ }
|
import scala.concurrent.duration.{ FiniteDuration, _ }
|
||||||
|
import scala.util.control.Exception.Catcher
|
||||||
|
|
||||||
import akka.stream.impl.Stages.DefaultAttributes
|
import akka.stream.impl.Stages.DefaultAttributes
|
||||||
import akka.util.OptionVal
|
import akka.util.OptionVal
|
||||||
|
|
||||||
|
|
@ -1938,19 +1939,28 @@ private[stream] object Collect {
|
||||||
try {
|
try {
|
||||||
currentIterator = plainFun(grab(in)).iterator
|
currentIterator = plainFun(grab(in)).iterator
|
||||||
pushPull()
|
pushPull()
|
||||||
} catch {
|
} catch handleException
|
||||||
|
|
||||||
|
override def onUpstreamFinish(): Unit = onFinish()
|
||||||
|
|
||||||
|
override def onPull(): Unit =
|
||||||
|
try pushPull()
|
||||||
|
catch handleException
|
||||||
|
|
||||||
|
private def handleException: Catcher[Unit] = {
|
||||||
case NonFatal(ex) ⇒ decider(ex) match {
|
case NonFatal(ex) ⇒ decider(ex) match {
|
||||||
case Supervision.Stop ⇒ failStage(ex)
|
case Supervision.Stop ⇒ failStage(ex)
|
||||||
case Supervision.Resume ⇒ if (!hasBeenPulled(in)) pull(in)
|
case Supervision.Resume ⇒
|
||||||
|
if (isClosed(in)) completeStage()
|
||||||
|
else if (!hasBeenPulled(in)) pull(in)
|
||||||
case Supervision.Restart ⇒
|
case Supervision.Restart ⇒
|
||||||
|
if (isClosed(in)) completeStage()
|
||||||
|
else {
|
||||||
restartState()
|
restartState()
|
||||||
if (!hasBeenPulled(in)) pull(in)
|
if (!hasBeenPulled(in)) pull(in)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
override def onUpstreamFinish(): Unit = onFinish()
|
|
||||||
|
|
||||||
override def onPull(): Unit = pushPull()
|
|
||||||
|
|
||||||
private def restartState(): Unit = {
|
private def restartState(): Unit = {
|
||||||
plainFun = f()
|
plainFun = f()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue