错误处理Scala:理解的未来 [英] Error handling Scala : Future For Comprehension
问题描述
我想在我的play scala Web应用程序中进行错误处理.
I want to do error handling in my play scala web application.
我的应用程序与数据库进行对话以获取一些行,它遵循以下流程.
My application talks to the data base to fetch some rows, it follows following flow.
- 第一次调用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
}
上面理解的每个方法都返回一个未来,这些方法的签名如下.
Every method in the comprehension above returns a future, the signature of these methods are as below.
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] {...}
在以下情况下如何处理错误/失败
How shall I do error/failure handling, in the following situation
- 当callFuture1无法从数据库获取数据时.我想回来 带有错误消息的适当的错误响应.从callFuture2开始 仅在callFuture1之后执行.我不想执行 如果callFuture1失败/出错并想返回,则调用callFuture2 立即出现错误消息. (对于callFuture2和 callFuture3)
- When callFuture1 fails to fetch data from database. I want to return a appropriate error response with error message. Since callFuture2 only gets executed after callFuture1. I dont want to execute callFuture2 if callFuture1 has failed/erred and would want to return error message immediately. (Same thing for callFuture2 and callFuture3)
-编辑-
当任何一个callFuture失败并且不继续进行后续的futureCalls时,我试图从getResponse()方法返回适当的错误响应.
I am trying to return an appropriate Error Response from getResponse() method, when either of the callFuture fails and not proceed to subsequent futureCalls.
基于Peter Neyens的回答,我尝试了以下操作,但给了我运行时错误.
I tried the following, based on Peter Neyens answer, but gave me an runtime error..
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
推荐答案
You could use the Future.recoverWith
function, to customize the exception if the Future
failed.
val failed = Future.failed(new Exception("boom"))
failed recoverWith {
case e: Exception => Future.failed(new Exception("A prettier error message", e)
}
这会使您的理解力变得更糟:
This will result in a slightly uglier for comprehension :
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
.
Note that you could also define your own exceptions to use instead of Exception
, if you want to add more information than just an error message.
如果您不希望细粒度的控件根据失败的Future
中的Throwable
设置不同的错误消息(如callFuture1
一样),则可以使用隐式类来丰富Future
来进行设置自定义错误消息稍微简单一些:
If you don't want fine grained control to set a different error message depending on the Throwable
in the failed Future
(like with callFuture1
), you could enrich Future
using an implicit class to set a custom error message somewhat simpler:
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
.
In both cases, using errorMsg
or recoverWith
directly, you still rely on Future
, so if a Future
fails the following Futures
will not be executed and you can directly use the error message inside the failed Future
.
您没有指定要如何处理错误消息.例如,如果要使用错误消息创建其他Response
,则可以使用recoverWith
或recover
.
You didn't specify how you would like to handle the error messages. If for example you want to use the error message to create a different Response
you could use recoverWith
or recover
.
future3 recover { case e: Exception =>
val errorMsg = e.getMessage
InternalServerError(errorMsg)
}
这篇关于错误处理Scala:理解的未来的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!