以下是我正在处理的演员接收部分的示例:
def receive = {
case "begin" =>
val listOfFutures: IndexedSeq[Future[Any]] = workers.map(worker => worker ? Work("test"))
val future: Future[IndexedSeq[Any]] = Future.sequence(listOfFutures)
future onComplete {
case Success(result) => println("Eventual result: "+result)
case Failure(ex) => println("Failure: "+ex.getMessage)
}
case msg => println("A message received: "+msg)
}
当其中一个工人的询问失败时(如果发生超时),序列未来将以失败告终。但是我想知道哪些工人失败了。有没有更优雅的方式,而不是简单地逐个映射listOfFutures而不使用 Future.sequence ?
答案 0 :(得分:7)
您可以使用未来的recover
方法来映射或包装基础异常:
import scala.concurrent.{Future, ExecutionContext}
case class WorkerFailed(name: String, cause: Throwable)
extends Exception(s"$name - ${cause.getMessage}", cause)
def mark[A](name: String, f: Future[A]): Future[A] = f.recover {
case ex => throw WorkerFailed(name, ex)
}
import ExecutionContext.Implicits.global
val f = (0 to 10).map(i => mark(s"i = $i", Future { i / i }))
val g = Future.sequence(f)
g.value // WorkerFailed: i = 0 - / by zero
答案 1 :(得分:2)
感谢@O__我已经提供了另一种可能更适合某些情况的解决方案。
case class WorkerDone(name: String)
case class WorkerFailed(name: String)
import ExecutionContext.Implicits.global
val f = (0 to 10).map {
i => Future {i/i; WorkerDone(s"worker$i")}.recover{
case ex => WorkerFailed(s"worker$i")
}
}
val futureSeq = Future.sequence(f)
futureSeq onComplete {
case Success(list) => list.collect {case result:WorkerFailed => result}.foreach {failed => println("Failed: "+failed.name)}
case Failure(ex) => println("Exception: "+ex.getMessage)
}
// just to make sure program doesn't end before onComplete is called.
Thread.sleep(2000L)
我不确定如果我的例子是一个好习惯,但我的目的是知道哪些工人失败了,无论他们如何失败。