我的应用程序与数据库进行交谈,以获取一些行,它遵循以下流程.
>首先调用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 举报,一经查实,本站将立刻删除。