2013-10-17 14 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("") 
} 

そして、これは、エラーをキャッチ。

私はスカラの未来のドキュメントをネット上で公開しましたが、復旧が私にとってうまくいかなかったのは困惑しています。

誰でも知っていますか?それを並べ替えるのに何が欠けていますか?

答えて

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()。未来はまだ起こっていないかもしれないことを表しています。そのことが例外をスローすると、その例外をrecoverで処理できます。しかし、あなたのケースでは、エラーはが作成される前にに起こっており、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) } 

例外が起こった未来を作成するために、コードの前に投げられたbeacuseあなたが最初の場所で、将来を作成したことがないので、明らかにそれは、動作しません。

解決策は、try catchブロック内の呼び出しをUserDao().getStuffOf(userId = userId).toList()にラップするか、呼び出す方法が何で失敗したのかを見つけてそこで例外をキャッチし、失敗した将来を返すことです。

+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") 
    } 
} 
関連する問題