微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

处理Scala的错误:理解的未来

我想在我的play scala web应用程序中进行错误处理.

我的应用程序与数据库进行交谈,以获取一些行,它遵循以下流程.

>首先调用db来获取一些数据
>使用第一次调用中的数据从db获取其他数据
>使用从最后两个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
  }

上述理解中的每种方法都会返回未来,这些方法的签名如下.

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] {...}

在以下情况下,如何进行错误/故障处理

当callFuture1无法从数据库获取数据时.我想回来
具有错误消息的适当的错误响应.由于callFuture2
只能在callFuture1之后执行.我不想执行
callFuture2如果callFuture1失败/错误,并希望返回
错误消息立即. (CallFuture2和
callFuture3)

– 编辑 –

我正在尝试从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功能,如果未来失败,则自定义异常.

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.

如果您不希望细粒度控制根据失败的未来中的Throwable设置不同的错误消息(如callFuture1),则可以使用隐式类来丰富Future,从而更简单地设置自定义错误消息:

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,因此如果将来未来失败,则将不会执行以下Futures,您可以直接在失败的Future中使用错误消息.

您没有指定如何处理错误消息.如果你想使用错误信息创建一个不同的响应,你可以使用recoverWith或recover.

future3 recover { case e: Exception =>
  val errorMsg = e.getMessage
  InternalServerError(errorMsg)
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐