错误处理 Scala:理解的未来 [英] Error handling Scala : Future For Comprehension

查看:28
本文介绍了错误处理 Scala:理解的未来的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在我的 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.

  1. 首先调用 db 来获取一些数据
  2. 使用第一次调用中的数据从数据库中获取其他数据
  3. 使用从最近两次 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
  }

上述推导式中的每个方法都返回一个future,这些方法的签名如下.

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 之后执行.我不想执行callFuture2 如果 callFuture1 失败/错误并且想要返回立即出现错误信息.( callFuture2 和callFuture3)

--编辑--

我正在尝试从 getResponse() 方法返回适当的错误响应,当任一 callFuture 失败并且不继续进行后续的 futureCalls 时.

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

推荐答案

您可以使用 Future.recoverWith 函数,用于自定义 Future 失败时的异常.

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

在这两种情况下,直接使用errorMsgrecoverWith,你仍然依赖于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,您可以使用 recoverWithrecover.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆