[英]Propagate errors through a chain of Scala futures
考慮一系列期貨,每個期貨返回 Either[Status, Resp]。 您將如何通過使用 Future 而不是 Either 的 for comprehension 傳播錯誤狀態代碼?
下面的代碼不起作用,因為解析異常沒有被最后一個未來的恢復捕獲
用例是 Scala Play ActionRefiners,它返回 Future[Either[Status, TRequest[A]]]。
def parseId(id: String):Future[Int] = {
Future.successful(Integer.parseInt(id))
}
def getItem(id: Int)(implicit ec: ExecutionContext): Future[Either[Status, String]] =
Future(Some("dummy res from db " + id)).transformWith {
case Success(opt) => opt match {
case Some(item) => Future.successful(Right(item))
case _ => Future.successful(Left(NotFound))
}
case Failure(_) => Future.successful(Left(InternalServerError))
}
(for {
id <- parseId("bad request")
resp <- getItem(id)
} yield resp).recover {
case _:NumberFormatException => Left(BadRequest)
}
我可以將 the.recover 移動到 parseId,但這使得 for 理解非常難看 - 必須在中間處理 Either[Status, id]
def parseId(id: String):Future[Either[Status, Int]] = {
Future.successful(Right(Integer.parseInt(id))).recover {
case _:NumberFormatException => Left(BadRequest)
}
}
你的異常沒有被捕獲,因為你沒有把它扔進Future
: Future.successful
立即滿足你給它的表達式的結果,如果它拋出異常,它會在當前線程上執行。
嘗試刪除.successful
: Future(id.toInt)
會做你想做的。
此外,我建議擺脫所有Either
s:這些被高度高估/過度使用,特別是在Future
的上下文中(無論如何已經將它們的結果包裝到Try
中),並且只是使代碼更復雜且可讀性更差而不提供很多好處。
case class FailureReason(status: Status)
extends Exception(status.toString)
def notFound() = throw FailureReason(NotFound)
def internalError() = throw FailureReason(InternalError)
def badRequest() = throw FailureReason(BadRequest)
def parseId(id: String):Future[Int] = Future(id.toInt)
def getItem(id: Int): Future[String] = Future(Some("dummy"))
.map { _.getOrElse(notFound) }
.recover { _ => internalError }
// this is the same as your for-comprehension, just looking less ugly imo :)
parseId("foo").flatMap(getItem).recover {
case _: NumberFormatException => badRequest()
}
// if you still want `Either` in the end for some reason:
.map(Right.apply[Status, String])
.recover {
case _: NumberFormatException => Left(BadRequest) // no need for the first recover above if you do this
case FailureReason(status) => Left(status)
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.