4

私の問題を説明する簡単なコードサンプル:

import scala.util._
import scala.concurrent._
import scala.concurrent.duration._
import ExecutionContext.Implicits.global

class LoserException(msg: String, dice: Int) extends Exception(msg) { def diceRoll: Int = dice }

def aPlayThatMayFail: Future[Int] = {
    Thread.sleep(1000) //throwing a dice takes some time...
    //throw a dice:
    (1 + Random.nextInt(6)) match {
        case 6 => Future.successful(6) //I win!
        case i: Int => Future.failed(new LoserException("I did not get 6...", i))
    }
}

def win(prefix: String): String = {
    val futureGameLog = aPlayThatMayFail
    futureGameLog.onComplete(t => t match {
        case Success(diceRoll) => "%s, and finally, I won! I rolled %d !!!".format(prefix, diceRoll)
        case Failure(e) => e match {
            case ex: LoserException => win("%s, and then i got %d".format(prefix, ex.diceRoll))
            case _: Throwable => "%s, and then somebody cheated!!!".format(prefix)
        }
    })
"I want to do something like futureGameLog.waitForRecursiveResult, using Await.result or something like that..."
}

win("I started playing the dice")   

この簡単な例は、私がやりたいことを示しています。基本的に、言葉で言えば、以前の成功または失敗した試行で異なるアクションを作成するときに、何らかの計算の結果を待ちたいと思います。

では、どのようにwinメソッドを実装しますか?

私の「現実世界」の問題は、違いがある場合はdispatch、非同期の http 呼び出しに使用しています。前の呼び出しが終了するたびに http 呼び出しを続けたいのですが、前の http 呼び出しが成功したかどうかによってアクションが異なります。

4

3 に答える 3

6

再帰呼び出しを使用して、失敗した未来を回復できます。

def foo(x: Int) = x match {
  case 10 => Future.successful(x)
  case _ => Future.failed[Int](new Exception)
}

def bar(x: Int): Future[Int] = {
  foo(x) recoverWith { case _ => bar(x+1) }
}

scala> bar(0)
res0: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@64d6601

scala> res0.value
res1: Option[scala.util.Try[Int]] = Some(Success(10))

recoverWithを受け取り、PartialFunction[Throwable,scala.concurrent.Future[A]]を返しますFuture[A]。ただし、ここで多くの再帰呼び出しを行うとかなりの量のメモリが使用されるため、注意が必要です。

于 2013-08-01T09:54:52.253 に答える
1

これは私のために働く:

def retryWithFuture[T](f: => Future[T],retries:Int, delay:FiniteDuration)    (implicit ec: ExecutionContext, s: Scheduler): Future[T] ={
    f.recoverWith { case _ if retries > 0 =>  after[T](delay,s)(retryWithFuture[T]( f , retries - 1 , delay)) }
}
于 2015-03-12T17:26:51.577 に答える