2016-04-15 23 views
2

メソッドの1つがcallfuture1()またはcallfuture2()の場合に例外をスローすると、次のコードでカスタムメッセージを返すようにします。将来のどちらかが失敗した場合、私の理解は、fが失敗した未来になるでしょう。将来のエラーから例外を処理できません

ただし、callfuture1が例外をスローした場合。 f.onFailureは実行されません。代わりに、例外の発生した標準のinternalErrorが返されるcallFuture1()のコード行でコールスタックが停止しているのがわかります。なぜそれが起こるのですか?

val f = for { 
x <- callfuture1() 
y <- callfuture2() 
} yield y 

f.onFailure { 
//send an internalserver error with some custom message 
} 

f.map { 
//send data back 
} 

==== ====更新

私は潜在的な問題は、その例外が今後の外に投げされているので、私のコードは、それが将来的に失敗したキャッチに失敗していることを、応答から見ます。 したがって、例外が将来発生するようなコードを変更しました。私はまだ私が見ている行動を説明することができません。 (それはプレイフレームワークとは何かを持っているのだろうか。)

def controllerfunction(id: String) = Action.async{ 

    val f = for{ 
    x <- callfuture1(id) 
    y <- callfuture2(x) 
    } yield y 

    y.onFailure{case t => 
    println("This gets printed"); 
    Ok("shit happened, but i am still ok")} 

    y.map{resp:String => Ok(resp)} 

} 

def callfuture1(id: String):Future[Obj1] = { 
    for { 
    val1 <- callfuture1.1(id) 
    val2 <- callfuture1.2(val1) 
    } yield val2 
} 

def callfuture1.2:Future[Obj3] = Future{ 
    thrown new Exception("TEST ME"); 
} 

def callfuture 1.1:Future[Obj4] = {...} 
def callfuture2: Future[String] = {....} 

期待。私の予想は(実行取得ん)、ONFAILURE実行されるべきであり、応答がなければならない返されたので 方法callfuture1.2は、将来の内部例外をスロー「くそが起こったが、私はまだ大丈夫だ」

実際 再生フレームワークでInternalServerErrorが返され、コンソールにエラースタックが表示されます。私はprintlin( "This gets gets printed")が実行されているのを見ます。

カントは何が起こっているのか理解しています。どんな洞察?

====更新2 =====

私は、プレイフレームワークのコントローラ内部で呼び出されたときに問題がのみ発生することを確認し(私はプレー2.5を使用しています)。スタンドアロンのスカラプログラムとして、これまでどおりに動作します。私は、再生エラー処理が未処理の例外をキャッチし、スタックトレースを出力すると信じています。私はこれが開発環境でのみ起こるべきだと思います。

+1

「val f1 = callfuture1(); val f2 = callfuture2; f = {x < - f1; y < - f2}はy 'を出力する。違いは、あなたの場合、先物が順番に実行されていることです(yはcallfuture1が完了するのを待っています)。 – chuwy

+0

「スタックが停止しました」とはどういう意味ですか? 「標準的な内部エラー」とは何ですか?あなたは 'onFailure'が実行されていないことをどのように知っていますか?実際のエラーとは何ですか? – Dima

+1

また。 'onFailure'は副作用にしか使えないことに注意してください。 'Future'に含まれる例外を変更することはできません。例外を抱く場合は、 'transform'または' recover'を使用する必要があります。 – Dima

答えて

2

これは、callfuture1が「未来のために」を投げた場合に起こります。 あなたの理解のためには、このに脱糖されています。すぐに(失敗した未来を返すとは反対に)、あなたはまだ例外をキャッチcallfuture2Future.flatMap内部で呼び出されたために失敗した将来、で終わるだろうスロー

val f = callfuture1.flatMap{ x => 
    callfuture2.map{ y => 
    y 
    } 
} 

callfuture2場合失敗した先物に変えます(Future.mapでも同じです)。

callfuture1の状況が異なります。すぐにスローすると、失敗した未来になるのはFuture.mapまたはFuture.flatMapです。一般的に

あなたはFutureを返し、エラーを投げることができる方法を避けるために試してみてください。 これは、callfuture1が投げることができるものを実行した場合、それを捕らえて失敗した未来の例外を回してから復帰する必要があることを意味します。

UPDATE:すでにコメントでディマによって示唆

Future.onFailureは、副作用のためだけに使用することができます:あなたは「たわごとが起こったが、私はまだ大丈夫だ」返されることが期待される方法についてのあなたの更新については。先物は不変です。失敗した例外から復旧したい場合は、元の(失敗した)未来を変更する方法はなく、実際に行うことができるのはそれを新しい未来に変えることだけです。 Future.recoverをご覧ください。それはあなたが必要とするものを正確に行います。つまり、失敗した結果があればそれを照合し、成功した将来に変えることで、入力された未来を変えることができます。これはcatch節と同じですが、先物の場合は同じです。具体的には、次のようなものです:

def controllerfunction(id: String) = Action.async{ 
    val f = for{ 
    x <- callfuture1(id) 
    y <- callfuture2(x) 
    } yield y 

    f.map{ resp: String => 
    Ok(resp) 
    }.recover{ 
    case t: Throwable => 
     println("This gets printed"); 
     Ok("shit happened, but i am still ok") 
    } 
} 
+0

質問を更新しました。私は将来の外に投げ出される例外の問題に対処しましたが、私はまだ私が説明することができない振る舞いを見ています:(何かの洞察?) – konquestor

+0

私の更新を見てください –

0

callfuture1()の内側にあなたが

def callfuture1(): Future[?] = Future { 
    val x = ... 
    x 
} 

のような未来のコンストラクタ内のすべてのプロセスをラップしていないようだが、それは将来の外なので、あなたのコードは

def callfuture1(): Future[?] = { 
    val x = ... // some error happen here 
    Future(x) 
} 

そうであるように思わあなたエラーが直接あなたのプログラムコードにスローされています

+0

答えは質問をする場所ではなく、コメントを使用してください。 –

+0

私は知っていますが、今は十分な評判がありません – bthuillier

関連する問題