+str #15750 Prototype of stream supervision
* add supervion for stages and built in ops run by interpreter * add supervision for mapAsync and mapAsyncUnordered * add supervision to groupBy and splitWhen * reference doc for scala and java
This commit is contained in:
parent
3b46966240
commit
693dcbefcc
33 changed files with 1563 additions and 179 deletions
|
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* Copyright (C) 2015 Typesafe Inc. <http://www.typesafe.com>
|
||||
*/
|
||||
package docs.stream
|
||||
|
||||
import scala.concurrent.Await
|
||||
import akka.stream.ActorFlowMaterializer
|
||||
import akka.stream.ActorFlowMaterializerSettings
|
||||
import akka.stream.Supervision
|
||||
import akka.stream.scaladsl._
|
||||
import akka.stream.testkit.AkkaSpec
|
||||
|
||||
class FlowErrorDocSpec extends AkkaSpec {
|
||||
|
||||
"demonstrate fail stream" in {
|
||||
//#stop
|
||||
implicit val mat = ActorFlowMaterializer()
|
||||
val source = Source(0 to 5).map(100 / _)
|
||||
val result = source.runWith(Sink.fold(0)(_ + _))
|
||||
// division by zero will fail the stream and the
|
||||
// result here will be a Future completed with Failure(ArithmeticException)
|
||||
//#stop
|
||||
|
||||
intercept[ArithmeticException] {
|
||||
Await.result(result, remaining)
|
||||
}
|
||||
}
|
||||
|
||||
"demonstrate resume stream" in {
|
||||
//#resume
|
||||
val decider: Supervision.Decider = exc => exc match {
|
||||
case _: ArithmeticException => Supervision.Resume
|
||||
case _ => Supervision.Stop
|
||||
}
|
||||
implicit val mat = ActorFlowMaterializer(
|
||||
ActorFlowMaterializerSettings(system).withSupervisionStrategy(decider))
|
||||
val source = Source(0 to 5).map(100 / _)
|
||||
val result = source.runWith(Sink.fold(0)(_ + _))
|
||||
// the element causing division by zero will be dropped
|
||||
// result here will be a Future completed with Success(228)
|
||||
//#resume
|
||||
|
||||
Await.result(result, remaining) should be(228)
|
||||
}
|
||||
|
||||
"demonstrate resume section" in {
|
||||
//#resume-section
|
||||
implicit val mat = ActorFlowMaterializer()
|
||||
val decider: Supervision.Decider = exc => exc match {
|
||||
case _: ArithmeticException => Supervision.Resume
|
||||
case _ => Supervision.Stop
|
||||
}
|
||||
val source = Source(0 to 5).section(OperationAttributes.supervisionStrategy(decider)) {
|
||||
_.filter(100 / _ < 50).map(elem => 100 / (5 - elem))
|
||||
}
|
||||
val result = source.runWith(Sink.fold(0)(_ + _))
|
||||
// the elements causing division by zero will be dropped
|
||||
// result here will be a Future completed with Success(150)
|
||||
//#resume-section
|
||||
|
||||
Await.result(result, remaining) should be(150)
|
||||
}
|
||||
|
||||
"demonstrate restart section" in {
|
||||
//#restart-section
|
||||
implicit val mat = ActorFlowMaterializer()
|
||||
val decider: Supervision.Decider = exc => exc match {
|
||||
case _: IllegalArgumentException => Supervision.Restart
|
||||
case _ => Supervision.Stop
|
||||
}
|
||||
val source = Source(List(1, 3, -1, 5, 7)).section(
|
||||
OperationAttributes.supervisionStrategy(decider)) {
|
||||
_.scan(0) { (acc, elem) =>
|
||||
if (elem < 0) throw new IllegalArgumentException("negative not allowed")
|
||||
else acc + elem
|
||||
}
|
||||
}
|
||||
val result = source.grouped(1000).runWith(Sink.head)
|
||||
// the negative element cause the scan stage to be restarted,
|
||||
// i.e. start from 0 again
|
||||
// result here will be a Future completed with Success(Vector(0, 1, 0, 5, 12))
|
||||
//#restart-section
|
||||
|
||||
Await.result(result, remaining) should be(Vector(0, 1, 0, 5, 12))
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -22,6 +22,7 @@ import akka.stream.scaladsl.OperationAttributes
|
|||
import scala.concurrent.ExecutionContext
|
||||
import akka.stream.ActorFlowMaterializerSettings
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
import akka.stream.Supervision
|
||||
|
||||
object IntegrationDocSpec {
|
||||
import TwitterStreamQuickstartDocSpec._
|
||||
|
|
@ -52,6 +53,13 @@ object IntegrationDocSpec {
|
|||
Future.successful(Some(handle.hashCode.toString))
|
||||
}
|
||||
|
||||
class AddressSystem2 {
|
||||
//#email-address-lookup2
|
||||
def lookupEmail(handle: String): Future[String] =
|
||||
//#email-address-lookup2
|
||||
Future.successful(handle + "@somewhere.com")
|
||||
}
|
||||
|
||||
final case class Email(to: String, title: String, body: String)
|
||||
final case class TextMessage(to: String, body: String)
|
||||
|
||||
|
|
@ -159,6 +167,22 @@ class IntegrationDocSpec extends AkkaSpec(IntegrationDocSpec.config) {
|
|||
probe.expectMsg("akkateam@somewhere.com")
|
||||
}
|
||||
|
||||
"lookup email with mapAsync and supervision" in {
|
||||
val addressSystem = new AddressSystem2
|
||||
val authors: Source[Author] =
|
||||
tweets.filter(_.hashtags.contains(akka)).map(_.author)
|
||||
|
||||
//#email-addresses-mapAsync-supervision
|
||||
import OperationAttributes.supervisionStrategy
|
||||
import Supervision.resumingDecider
|
||||
|
||||
val emailAddresses: Source[String] =
|
||||
authors.section(supervisionStrategy(resumingDecider)) {
|
||||
_.mapAsync(author => addressSystem.lookupEmail(author.handle))
|
||||
}
|
||||
//#email-addresses-mapAsync-supervision
|
||||
}
|
||||
|
||||
"calling external service with mapAsyncUnordered" in {
|
||||
val probe = TestProbe()
|
||||
val addressSystem = new AddressSystem
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue