我目前正在尝试一次解决多个期货,但是由于其中一些可能会失败,因此如果其中一个失败,我不想全部失败,而是以Map(String, AnyRef)
结尾(表示具有将来名称的Map,并将响应转换为所需的地图。
目前,我有以下内容:
val fsResp = channelList.map {
channelRef => channelRef.ask(ReportStatus).mapTo[EventMessage]
}
Future.sequence(fsResp).onComplete{
case Success(resp: Seq[EventMessage]) =>
resp.foreach { event => Supervisor.foreach(_ ! event) }
val channels = loadConfiguredComponents()
.collect {
case ("processor" | "external", components) => components.map {
case (name, config: Channel) =>
(name, serializeDetails(config, resp.find(_.channel == ChannelName(name))))
}
}.flatten.toMap
val event = EventMessage(...)
Supervisor.foreach(_ ! event)
case Failure(exception) => originalSender ! replayError(exception.getMessage)
}
但是,如果其中任何一个失败,则此操作将失败。那我怎么能得到Map(channelRef.path.name, event() | exception)
呢?
谢谢!
答案 0 :(得分:1)
您可以使用fallbackTo以避免失败。在此示例中,我将Future [T]更改为Future [Option [T]],以回退到None,然后删除None元素。
import scala.concurrent.ExecutionContext.Implicits.global
def method(value:Int) = { Thread.sleep(2000); println(value); value }
println("start")
val eventualNone = Future.successful(None)
val futures = List(Future(method(1)), Future(method(2)), Future(method(3)), Future(throw new RuntimeException))
val withoutFailures = futures.map(_.map(Option.apply).fallbackTo(eventualNone))
Future.sequence(withoutFailures).map(_.flatten).onComplete {
case Success(values) => println(values)
case Failure(ex:Throwable) => println("FAIL")
}
Thread.sleep(5000)
输出
start
1
3
2
List(1, 2, 3)
如果您想知道失败的原因,可以将其更改为Either [Throwable,T]而不是Option [T]。
此代码始终为Success(关于Future结果),因此您需要检查您的值以了解所有期货是否失败。
答案 1 :(得分:0)
要从期货列表中捕获成功/失败值,您可以首先将map/recover
应用于每个期货,然后使用Future.sequence
将结果列表转换为List[Either[Throwable,EventMessage]]
的期货,如以下简单示例所示:
import scala.concurrent.{Future, Await}
import scala.concurrent.duration._
import scala.concurrent.ExecutionContext.Implicits.global
case class EventMessage(id: Int, msg: String)
val fsResp = List(
Future{EventMessage(1, "M1")}, Future{throw new Throwable()}, Future{EventMessage(3, "M3")}
)
val f = Future.sequence(
fsResp.map( _.map{ resp =>
// Do stuff with `resp`, add item to `Map()`, etc ...
Right(resp)
}.
recover{ case e: Throwable =>
// Log `exception` info, etc ...
Left(e)
} )
)
Await.result(f, Duration.Inf)
// f: scala.concurrent.Future[List[Product with Serializable with scala.util.
// Either[Throwable,EventMessage]]] = Future(Success(List(
// Right(EventMessage(1,M1)), Left(java.lang.Throwable), Right(EventMessage(3,M3))
// )))