如何继续执行未来序列尽管失败? [英] How to carry on executing Future sequence despite failure?

查看:151
本文介绍了如何继续执行未来序列尽管失败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

遍历方法从未来对象在第一次失败时停止。我想要一个宽容/宽容的版本的这种方法,发生错误时,继续其余的序列。



目前我们已将以下方法添加到我们的工具中:

  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] )。下面是我们如何实现它:

  //也可以更简洁b // f.map(Success(_))。recover {case t:Throwable =>失败(t)} 
//注意:你可能还想将它移动到一个富集类
def mapValue [T](f:Future [T]):Future [Try [T]] = {
val prom = Promise [Try [T]]()
f onComplete prom.success
prom.future
}
pre>

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

  traverse(seq)(f andThen mapValue)

您将获得成功未来[Seq [Try [A]]] ,其最终值包含每个成功未来的成功实例, > 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})
}


The traverse method from Future object stops at first failure. I want a tolerant/forgiving version of this method which on occurrence of errors carries on with the rest of the sequence.

Currently we have added the following method to our 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
}

Is there a better way to do this?

解决方案

A genuinely useful thing (generally speaking) would be to be able to promote the error of a future into a proper value. Or in other words, transform a Future[T] into a Future[Try[T]] (the succesful return value becomes a Success[T] while the failure case becomes a Failure[T]). Here is how we might implement it:

// 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
}

Now, if you do the following:

Future.traverse(seq)( f andThen mapValue )

You'll obtain a succesful Future[Seq[Try[A]]], whose eventual value contains a Success instance for each successful future, and a Failure instance for each failed future. If needed, you can then use collect on this seq to drop the Failure instances and keep only the sucessful values.

In other words, you can rewrite your helper method as follows:

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 } )
}

这篇关于如何继续执行未来序列尽管失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆