2013-10-17 47 views
19

我正在使用Scala,Play Framework 2.1.x和reactivemongo驱动程序。为什么Future的恢复不会捕获异常?

我有一个API调用:

def getStuff(userId: String) = Action(implicit request => { 
    Async { 
     UserDao().getStuffOf(userId = userId).toList() map { 
     stuffLst => Ok(stuffLst) 
     } 
    } 
}) 

它工作的时间细99%,但有时可能会失败(没关系,为什么,这不是问题)。

我想在一个错误的情况下恢复,所以我说:

recover { case _ => BadRequest("")} 

但这不从错误中恢复了我。
我试过Scala的控制台上相同的概念和它的工作:

import scala.concurrent._ 
import scala.concurrent.duration._ 
import ExecutionContext.Implicits.global 
var f = future { throw new Exception("") } map {_ => 2} recover { case _ => 1} 
Await.result(f, 1 nanos) 

预期这将返回1。
我目前包裹异步有:

try{ 
    Async {...} 
} catch { 
    case _ => BadRequest("") 
} 

这抓住了错误。

我在网上浏览了一些Scala的Future文档,我很困惑为什么恢复不适合我。

有谁知道为什么?我想把它排除在外?

回答

40

为什么它失败其实很重要100%。如果我们通过几行代码的传播代码,你就会明白为什么:

def getStuff(userId: String) = Action(implicit request => { 
    Async { 
    val future = UserDao().getStuffOf(userId = userId).toList() 
    val mappedFuture = future.map { 
     stuffLst => Ok(stuffLst) 
    } 
    mappedFuture.recover { case _ => BadRequest("")} 
    } 
}) 

所以,UserDao().getStuffOf(userId = userId).toList()回报你的未来。未来代表着可能还没有发生的事情。如果该事件引发异常,则可以在恢复中处理该异常。但是,在你的情况下,错误发生在未来甚至被创建之前UserDao().getStuffOf(userId = userId).toList()调用抛出异常,不会返回未来。因此,恢复未来的呼声永远不会被执行。这相当于在斯卡拉REPL这样做:

import scala.concurrent._ 
import scala.concurrent.duration._ 
import ExecutionContext.Implicits.global 
var f = { throw new Exception(""); future { "foo" } map {_ => 2} recover { case _ => 1} } 
Await.result(f, 1 nanos) } 

显然是行不通的,因为你从来没有在第一时间创建的未来怎么一回事,因为异常是代码来创建未来发生之前抛出。

因此,解决方案是将你的调用打包到try catch块中,或者找出它在调用的任何方法中失败的原因,并捕获异常并返回失败的未来。

+0

到底什么是“失败的未来”? – ps0604

+0

@ ps0604:'Future.failed(<你抓到的异常>)' –

4

如果你有玩如2.2.x的更高版本,你可以这样做:

def urlTest() = Action.async { 
    val holder: WSRequestHolder = WS.url("www.idontexist.io") 
    holder.get.map { 
     response => 
     println("Yay, I worked") 
     Ok 
    }.recover { 
     case _ => 
     Log.error("Oops, not gonna happen") 
     InternalServerError("Failure") 
    } 
} 
相关问题