22

我正在使用 Scala、Play Framework 2.1.x 和 reactivemongo 驱动程序。

我有一个 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。
我目前将 Async 包装为:

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

这会捕获错误。

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

有谁知道为什么?我想念什么来解决它?

4

2 回答 2

47

为什么它失败实际上是 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()调用正在引发异常,而不是返回未来。所以恢复未来的调用永远不会被执行。这相当于在 Scala 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) }

显然这是行不通的,因为你从来没有创建过未来,因为在创建未来的代码发生之前就抛出了异常。

因此,解决方案是将您的调用包装UserDao().getStuffOf(userId = userId).toList()在一个 try catch 块中,或者找出它在您调用的任何方法中失败的原因,并在那里捕获异常,并返回一个失败的未来。

于 2013-10-18T03:43:21.117 回答
4

如果你有更高版本的 Play,例如 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")
    }
}
于 2014-03-24T00:11:19.727 回答