如何在流中捕获未来失败的异常

时间:2017-05-22 14:38:12

标签: scala akka akka-http akka-stream

我正在尝试创建一个轮询一个休息服务并解组json对象的流。

我创建了一个source.tick,每5秒执行一次http请求。如果成功,HttpResponse将包含OK。如果不是,则该服务不可用。结果将发送给演员。请参阅以下代码:

def poll(pollActor: ActorRef) {

    val source = Source.tick(0.seconds, 3.seconds, HttpRequest(uri = Uri(path = Path("/posts/1"))))

    val flow = Http().outgoingConnectionHttps("jsonplaceholder1.typicode.com").mapAsync(1) {
      case HttpResponse(StatusCodes.OK, _, entity, _) =>
        Unmarshal(entity).to[Item]
      case resp @ HttpResponse(code, _, _, _) =>
        log.warning("Request failed, response code: " + code)
        Future.failed(new Exception)
    }

    source.via(flow).runWith(Sink.actorRef[Equals](pollActor,akka.actor.Status.Success(())))
}

actor将从流中接收结果,如以下代码所示:

def receive = {
    case k : Item => println(k)
    case f : Failure => {
      println("We failed: " + f)
    }
}

我应该在何处以及如何处理未来抛出的异常?

2 个答案:

答案 0 :(得分:0)

解决此问题的一种方法是将故障视为流的明确部分。

    val flow = Http().outgoingConnectionHttps("jsonplaceholder1.typicode.com").mapAsync(1) {
      case HttpResponse(StatusCodes.OK, _, entity, _) =>
        Unmarshal(entity).to[Item].map(Right(_))
      case resp @ HttpResponse(code, _, _, _) =>
        Future.successful(Left(MyDomainFailure("some meaningful message/data")))
    }

请注意,现在流的类型是

Flow[HttpRequest, Either[MyDomainFailure, Item], Future[OutgoingConnection]] 

这具有清晰度的附加值,使得下游阶段意识到失败并迫使他们处理它(好吧,在这种情况下不是真的,因为你正在使用一个演员。如果你保持在...的范围内溪流,你将被迫处理它们。)

    def receive = {
      case Right(item) => println(item)
      case Left(failure) => {
        println("We failed: " + failure.msg)
      }
    }

答案 1 :(得分:0)

这是我使用的修复程序,虽然它没有产生异常,Failure中包含的HttpResponse只是在接收函数中匹配。

def poll(pollActor: ActorRef) {

  val source = Source.tick(0.seconds, 3.seconds, HttpRequest(uri = Uri(path = Path("/posts/1"))))

  val flow = Http().outgoingConnectionHttps("jsonplaceholder1.typicode.com").mapAsync(1) {
    // Where able to reach the API.
    case HttpResponse(StatusCodes.OK, _, entity, _) =>
      // Unmarshal the json response.
      Unmarshal(entity).to[Item]

    // Failed to reach the API.
    case HttpResponse(code, _, _, _) =>
      Future.successful(code)
  }

    source.via(flow).runWith(Sink.actorRef[Any](pollActor,akka.actor.Status.Success(())))
}

此处我们匹配Failure生成的HttpResponse

def receive = {
  case item: Item => println(item)
  case failure: Failure => {
    log.warning("Request failed, response code: " + failure)
  }
}