【问题标题】:Retry a function that returns a Future重试返回 Future 的函数
【发布时间】:2020-03-20 19:04:36
【问题描述】:

假设我有一个函数foo,它执行异步计算并返回一个Future

def foo(x: Int)(implicit ec: ExecutionContext): Future[Int] = ???

现在我想重试这个计算n 次,直到计算成功。

def retryFoo(x: Int, n: Int)(implicit ec: ExecutionContext): Future[Int] = ???

我还想返回重试时抛出的所有个异常。因此,我定义了新的异常类 ExceptionsList 并要求 retryFoo 在所有重试失败时返回 ExceptionsList

case class ExceptionsList(es: List[Exception]) extends Exception { ... }  

您将如何编写retryFoo 以重试foo 并返回带有foo 结果或ExceptionsListFuture

【问题讨论】:

  • 是否应该仅在方法最终失败时才返回异常列表?或者,例如,重试限制为 5,并且方法在第 3 次尝试时成功,它是否应该返回前两次失败的结果和异常?
  • 谢谢,好问题!我写道,只有当 all 重试失败时才需要例外。然而,即使最后一次重试成功,返回之前的异常也是有意义的。

标签: scala exception future


【解决方案1】:

我可能会这样做:

final case class ExceptionsList(es: List[Throwable]) extends Throwable
def retry[T](n: Int, expr: => Future[T], exs: List[Throwable] = Nil)(implicit ec: ExecutionContext): Future[T] =
  Future.unit.flatMap(_ => expr).recoverWith {
    case e if n > 0 => retry(n - 1, expr, e :: exs)
    case e => Future.failed(new ExceptionsList(e :: exs))
  }

expr 是按名称调用的,因为它本身可以抛出异常而不是返回失败的 Future。我将累积的异常记录在一个列表中,但我想这是一种品味。

【讨论】:

    【解决方案2】:

    您可以使用 Future 的 transformWith 和一点递归来进行重试。使用transformWith,您可以对未来的成功或失败进行模式匹配。在成功的情况下,您只需返回 Success 的结果即可,因为您不关心中间失败。在失败的情况下,您进行递归调用,减少重试次数并将异常附加到参数列表中的列表以跟踪所有失败。如果n 一直为零,则您已经用尽了重试。在这种情况下,您只需创建一个 ExceptionsList 的新实例,然后就失败了。

    下面的示例演示了所有期货都抛出异常时的失败情况。你可以打电话给retryFoo(3),你会得到一个失败的未来,除了三个例外。

    case class ExceptionsList(es: List[Throwable]) extends Exception
    
    def retryFoo(n: Int, exceptions: List[Throwable] = List())(implicit ec: ExecutionContext): Future[Int] = {
      if (n == 0) {
        Future.failed(ExceptionsList(exceptions))
      } else {
        Future {
          throw new Exception("fail!")
        }.transformWith {
          case Success(result) => Future(result)
          case Failure(ex) =>
            println("Retrying!")
            retryFoo(n - 1, exceptions :+ ex)
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-12-09
      • 1970-01-01
      • 1970-01-01
      • 2020-04-14
      • 2020-08-01
      • 2019-07-31
      • 2013-08-05
      相关资源
      最近更新 更多