私は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を返します。
私は現在、非同期を次のようにラップしています:
try{
Async {...}
} catch {
case _ => BadRequest("")
}
そして、これはエラーをキャッチします。
私はネットでScalaのFutureのドキュメントをいくつか調べましたが、なぜリカバリが機能しないのか困惑しています。
なぜ誰か知っていますか?それを整理するために私は何を見逃していますか?
失敗する理由は、実際には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ブロックでラップするか、呼び出すメソッドで失敗している理由を見つけ、そこで例外をキャッチし、失敗したfutureを返すことです。
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")
}
}