繁体   English   中英

尽管失败,如何继续执行Future序列?

[英]How to carry on executing Future sequence despite failure?

Future对象的traverse方法在第一次失败时停止。 我想要这种方法的宽容/宽容版本,在出现错误时继续执行序列的其余部分。

目前我们已经为我们的utils添加了以下方法:

def traverseFilteringErrors[A, B <: AnyRef]
                           (seq: Seq[A])
                           (f: A => Future[B]): Future[Seq[B]] = {
  val sentinelValue = null.asInstanceOf[B]
  val allResults = Future.traverse(seq) { x =>
    f(x) recover { case _ => sentinelValue }
  }
  val successfulResults = allResults map { result =>
    result.filterNot(_ == sentinelValue)
  }
  successfulResults
}

有一个更好的方法吗?

一般来说,一个真正有用的东西是能够将未来的错误推向一个适当的价值。 或者换句话说,将Future[T]转换为Future[Try[T]] (成功返回值变为Success[T]而失败案例变为Failure[T] )。 以下是我们如何实现它:

// Can also be done more concisely (but less efficiently) as:
// f.map(Success(_)).recover{ case t: Throwable => Failure( t ) }
// NOTE: you might also want to move this into an enrichment class
def mapValue[T]( f: Future[T] ): Future[Try[T]] = {
  val prom = Promise[Try[T]]()
  f onComplete prom.success
  prom.future
}

现在,如果您执行以下操作:

Future.traverse(seq)( f andThen mapValue )

您将获得一个成功的Future[Seq[Try[A]]] ,其最终值包含每个成功未来的Success实例,以及每个失败的未来的Failure实例。 如果需要,您可以在此seq上使用collect来删除Failure实例并仅保留成功的值。

换句话说,您可以按如下方式重写助手方法:

def traverseFilteringErrors[A, B](seq: Seq[A])(f: A => Future[B]): Future[Seq[B]] = {
  Future.traverse( seq )( f andThen mapValue ) map ( _ collect{ case Success( x ) => x } )
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM