具有错误累积功能的异步处理功能签名

时间:2019-12-15 19:01:28

标签: scala concurrency future

假设我有一个函数fab: A => Future[B]。现在,我需要编写新函数foo来处理Seq[A]并累积所有错误。这就是为什么我不能使用Future.traverse的原因,因为它“快速失败”并且不会累积错误。

foo收到Seq[A],并应返回Future。客户端应该为输入B的每个元素获取Seq[A]或一个异常。该函数的签名是什么?

2 个答案:

答案 0 :(得分:1)

要根据需要定义foo,请在将Future.sequence应用于输入列表的各个元素之后,考虑在map/recover上方使用fab,如下所示:< / p>

import scala.concurrent.{ Future, ExecutionContext }

def foo[A, B](ls: List[A])(fab: A => Future[B])(implicit ec: ExecutionContext):
    Future[List[Either[Throwable, B]]] =
  Future.sequence(ls.map(fab).map(_.map(Right(_)).recover{ case e => Left(e) }))

请注意,首选使用不可变的Seq而不是List,因此这里使用它。如有必要,将其更改为Seq

测试foo

implicit val ec = ExecutionContext.global

def fab(s: String): Future[Int] = Future{ 10 / s.length }

val ls = List("abcd", "", "xx", "")

foo(ls)(fab)
// res1: Future[List[Either[Throwable, Int]]] = Future(Success(List(
//   Right(2),
//   Left(java.lang.ArithmeticException: / by zero),
//   Right(5),
//   Left(java.lang.ArithmeticException: / by zero)
// )))

答案 1 :(得分:0)

我有ZIO的解决方案。

我添加了这个伪造的函数:

  def fab(implicit ec: ExecutionContext): Int => Future[String] = i => Future(
    if (i % 3 == 0)
      throw new IllegalArgumentException(s"bad $i")
    else
      s"$i"
  )

现在,我们创建Int的流,并为每个流运行fab

  val stream =
    ZStream.fromIterable(Seq(1, 2, 3, 4, 5))
      .map(in => Task.fromFuture(implicit ec => fab(ec)(in)))

  val sink = Sink.collectAll[Task[String]]

现在,我们收集成功和失败的信息:

  val collect: ZIO[zio.ZEnv, Throwable, (List[String], List[Throwable])] = for {
    strs <- stream.run(sink)
    successes <- Task.collectAllSuccesses(strs)
    failures <- ZIO.collectAllSuccesses(strs.map(_.flip))
  } yield (successes, failures)

运行并打印此内容

  new DefaultRuntime {}
    .unsafeRun(
      collect
        .tapError { ex => zio.console.putStrLn(s"There was an exception: ${ex.getMessage}") }
        .tap { case (successes, failures) => zio.console.putStrLn(s"($successes, $failures)") }
        .fold(_ => -1, _ => 0)
    )

打印我们:

(List(1, 2, 4, 5), List(java.lang.IllegalArgumentException: bad 3))

让我知道您是否需要更多说明-ZIO是否可以选择。