错误处理 Scala:理解的未来
Error handling Scala : Future For Comprehension
我想在我的 play scala web 应用程序中进行错误处理。
我的应用程序与数据库对话以获取一些行,它遵循以下流程。
- 首先调用 db 获取一些数据
- 使用第一次调用中的数据从数据库中获取其他数据
- 使用从最近两次数据库调用中收到的数据形成响应。
下面是我的伪代码。
def getResponse(name: String)
(implicit ctxt: ExecutionContext): Future[Response] = {
for {
future1 <- callFuture1(name)
future2 <- callFuture2(future1.data)
future3 <- callFuture3(future1.data, future2.data)
} yield future3
}
上面理解中的每个方法return都是一个未来,这些方法的签名如下。
private def callFuture1(name: String)
(implicit ctxt: ExecutionContext): Future[SomeType1] {...}
private def callFuture2(keywords: List[String])
(implicit ctxt: ExecutionContext): Future[SomeType2] {...}
private def callFuture3(data: List[SomeType3], counts: List[Int])
(implicit ctxt: ExecutionContext): Future[Response] {...}
遇到以下情况error/failure如何处理
- 当 callFuture1 无法从数据库中获取数据时。我要 return
带有错误消息的适当错误响应。自从 callFuture2
仅在 callFuture1 之后执行。我不想执行
callFuture2 如果 callFuture1 有 failed/erred 并且想要 return
错误信息立即。 (对于 callFuture2 和
callFuture3)
--编辑--
我正在尝试 return 来自 getResponse() 方法的适当错误响应,当任一 callFuture 失败并且不继续进行后续 futureCalls 时。
我根据 Peter Neyens 的回答尝试了以下方法,但给了我一个运行时错误..
def getResponse(name: String)
(implicit ctxt: ExecutionContext): Future[Response] = {
for {
future1 <- callFuture1(name) recoverWith {
case e:Exception => return Future{Response(Nil,Nil,e.getMessage)}
}
future2 <- callFuture2(future1.data)
future3 <- callFuture3(future1.data, future2.data)
} yield future3
}
我得到运行时错误
ERROR] [08/31/2015 02:09:45.011] [play-akka.actor.default-dispatcher-3] [ActorSystem(play)] Uncaught error from thread [play-akka.actor.default-dispatcher-3] (scala.runtime.NonLocalReturnControl)
[error] a.a.ActorSystemImpl - Uncaught error from thread [play-akka.actor.default-dispatcher-3]
scala.runtime.NonLocalReturnControl: null
您可以使用 Future.recoverWith
函数,在 Future
失败时自定义异常。
val failed = Future.failed(new Exception("boom"))
failed recoverWith {
case e: Exception => Future.failed(new Exception("A prettier error message", e)
}
这会导致理解有点难看:
for {
future1 <- callFuture1(name) recoverWith {
case npe: NullPointerException =>
Future.failed(new Exception("how did this happen in Scala ?", npe))
case e: IllegalArgumentException =>
Future.failed(new Exception("better watch what you give me", e))
case t: Throwable =>
Future.failed(new Exception("pretty message A", t))
}
future2 <- callFuture2(future1.data) recoverWith {
case e: Exception => Future.failed(new Exception("pretty message B", e))
}
future3 <- callFuture3(future1.data, future2.data) recoverWith {
case e: Exception => Future.failed(new Exception("pretty message C", e))
}
} yield future3
请注意,如果您想添加更多信息而不仅仅是错误消息,您也可以定义自己的异常来代替 Exception
。
如果您不希望细粒度控制根据失败的 Future
中的 Throwable
设置不同的错误消息(与 callFuture1
一样),您可以丰富 Future
使用隐式 class 设置自定义错误消息稍微简单一些:
implicit class ErrorMessageFuture[A](val future: Future[A]) extends AnyVal {
def errorMsg(error: String): Future[A] = future.recoverWith {
case t: Throwable => Future.failed(new Exception(error, t))
}
}
你可以像这样使用:
for {
future1 <- callFuture1(name) errorMsg "pretty A"
future2 <- callFuture2(future1.data) errorMsg "pretty B"
future3 <- callFuture3(future1.data, future2.data) errorMsg "pretty C"
} yield future3
在这两种情况下,直接使用 errorMsg
或 recoverWith
,您仍然依赖 Future
,因此如果 Future
失败,则以下 Futures
将不执行,可以直接使用失败的Future
.
里面的错误信息
您没有指定您希望如何处理错误消息。例如,如果您想使用错误消息创建不同的 Response
,您可以使用 recoverWith
或 recover
.
future3 recover { case e: Exception =>
val errorMsg = e.getMessage
InternalServerError(errorMsg)
}
说 future1
、future2
和 future3
分别抛出名为 Future1Exception
、Future2Exception
和 Future3Exception
的 Throwable
异常.然后你可以 return 适当的错误 Response
从 getResponse()
方法如下:
def getResponse(name: String)
(implicit ctxt: ExecutionContext): Future[Response] = {
(for {
future1 <- callFuture1(name)
future2 <- callFuture2(future1.data)
future3 <- callFuture3(future1.data, future2.data)
} yield future3).recover {
case e: Future1Exception =>
// build appropriate Response(...)
case e: Future2Exception =>
// build appropriate Response(...)
case e: Future3Exception =>
// build appropriate Response(...)
}
}
根据文档Future.recover
Creates a new future that will handle any matching throwable that this
future might contain.
我想在我的 play scala web 应用程序中进行错误处理。
我的应用程序与数据库对话以获取一些行,它遵循以下流程。
- 首先调用 db 获取一些数据
- 使用第一次调用中的数据从数据库中获取其他数据
- 使用从最近两次数据库调用中收到的数据形成响应。
下面是我的伪代码。
def getResponse(name: String)
(implicit ctxt: ExecutionContext): Future[Response] = {
for {
future1 <- callFuture1(name)
future2 <- callFuture2(future1.data)
future3 <- callFuture3(future1.data, future2.data)
} yield future3
}
上面理解中的每个方法return都是一个未来,这些方法的签名如下。
private def callFuture1(name: String)
(implicit ctxt: ExecutionContext): Future[SomeType1] {...}
private def callFuture2(keywords: List[String])
(implicit ctxt: ExecutionContext): Future[SomeType2] {...}
private def callFuture3(data: List[SomeType3], counts: List[Int])
(implicit ctxt: ExecutionContext): Future[Response] {...}
遇到以下情况error/failure如何处理
- 当 callFuture1 无法从数据库中获取数据时。我要 return 带有错误消息的适当错误响应。自从 callFuture2 仅在 callFuture1 之后执行。我不想执行 callFuture2 如果 callFuture1 有 failed/erred 并且想要 return 错误信息立即。 (对于 callFuture2 和 callFuture3)
--编辑--
我正在尝试 return 来自 getResponse() 方法的适当错误响应,当任一 callFuture 失败并且不继续进行后续 futureCalls 时。
我根据 Peter Neyens 的回答尝试了以下方法,但给了我一个运行时错误..
def getResponse(name: String)
(implicit ctxt: ExecutionContext): Future[Response] = {
for {
future1 <- callFuture1(name) recoverWith {
case e:Exception => return Future{Response(Nil,Nil,e.getMessage)}
}
future2 <- callFuture2(future1.data)
future3 <- callFuture3(future1.data, future2.data)
} yield future3
}
我得到运行时错误
ERROR] [08/31/2015 02:09:45.011] [play-akka.actor.default-dispatcher-3] [ActorSystem(play)] Uncaught error from thread [play-akka.actor.default-dispatcher-3] (scala.runtime.NonLocalReturnControl)
[error] a.a.ActorSystemImpl - Uncaught error from thread [play-akka.actor.default-dispatcher-3]
scala.runtime.NonLocalReturnControl: null
您可以使用 Future.recoverWith
函数,在 Future
失败时自定义异常。
val failed = Future.failed(new Exception("boom"))
failed recoverWith {
case e: Exception => Future.failed(new Exception("A prettier error message", e)
}
这会导致理解有点难看:
for {
future1 <- callFuture1(name) recoverWith {
case npe: NullPointerException =>
Future.failed(new Exception("how did this happen in Scala ?", npe))
case e: IllegalArgumentException =>
Future.failed(new Exception("better watch what you give me", e))
case t: Throwable =>
Future.failed(new Exception("pretty message A", t))
}
future2 <- callFuture2(future1.data) recoverWith {
case e: Exception => Future.failed(new Exception("pretty message B", e))
}
future3 <- callFuture3(future1.data, future2.data) recoverWith {
case e: Exception => Future.failed(new Exception("pretty message C", e))
}
} yield future3
请注意,如果您想添加更多信息而不仅仅是错误消息,您也可以定义自己的异常来代替 Exception
。
如果您不希望细粒度控制根据失败的 Future
中的 Throwable
设置不同的错误消息(与 callFuture1
一样),您可以丰富 Future
使用隐式 class 设置自定义错误消息稍微简单一些:
implicit class ErrorMessageFuture[A](val future: Future[A]) extends AnyVal {
def errorMsg(error: String): Future[A] = future.recoverWith {
case t: Throwable => Future.failed(new Exception(error, t))
}
}
你可以像这样使用:
for {
future1 <- callFuture1(name) errorMsg "pretty A"
future2 <- callFuture2(future1.data) errorMsg "pretty B"
future3 <- callFuture3(future1.data, future2.data) errorMsg "pretty C"
} yield future3
在这两种情况下,直接使用 errorMsg
或 recoverWith
,您仍然依赖 Future
,因此如果 Future
失败,则以下 Futures
将不执行,可以直接使用失败的Future
.
您没有指定您希望如何处理错误消息。例如,如果您想使用错误消息创建不同的 Response
,您可以使用 recoverWith
或 recover
.
future3 recover { case e: Exception =>
val errorMsg = e.getMessage
InternalServerError(errorMsg)
}
说 future1
、future2
和 future3
分别抛出名为 Future1Exception
、Future2Exception
和 Future3Exception
的 Throwable
异常.然后你可以 return 适当的错误 Response
从 getResponse()
方法如下:
def getResponse(name: String)
(implicit ctxt: ExecutionContext): Future[Response] = {
(for {
future1 <- callFuture1(name)
future2 <- callFuture2(future1.data)
future3 <- callFuture3(future1.data, future2.data)
} yield future3).recover {
case e: Future1Exception =>
// build appropriate Response(...)
case e: Future2Exception =>
// build appropriate Response(...)
case e: Future3Exception =>
// build appropriate Response(...)
}
}
根据文档Future.recover
Creates a new future that will handle any matching throwable that this future might contain.