具有 Future 返回类型的 Scala 递归函数

标签 scala concurrency

我正在 scala 中编写一个递归重试函数,我想知道 future 的创建是否存在运行时错误。如果存在则重试 future 的实例化。

假设我有一个数据库查询功能:

dbLookup(userId : UserId) : Option[UserName] = ???

重试的形式如下:

retry[T](f : () => Future[Option[T]],  
         notifyFailure : (t : Throwable) => Unit,
         n : Int) : Future[Option[T]] = {
  if(n <= 0) { Future{None} }
  else {
    val fut = f()
    if(f.resultsInException) {      //I don't know how to write this
      notifyFailure(f.exception)
      retry(f, notifyFailure, n-1) //try again
    }
    else {
      f.originalValueAsFuture
    }
  }
}

如何实现这一 future 功能并允许尾递归优化?

如果当我尝试创建 Future 时执行上下文不断抛出异常,则可以使用此函数为用户重试数据库 10 次:

val userNameAfterRetries = 
  retry(() => Future{dbLookup("1234")},
        (t) => system error (s"future creation error : $t"),
        10)

注意:这在 Future.fallbackTo 中是可能的,但不幸的是,fallbackTo 接受的是 Future[T] 而不是 () => Future [T]。这很重要,因为即使第一次尝试成功,使用 FallbackTo 也会导致至少重试 1 次。

预先感谢您的考虑和回复。

最佳答案

这个怎么样?

  def retry[T](f: () => Future[Option[T]],
               notifyFailure: Throwable => Unit,
               n: Int)(implicit ec : ExecutionContext): Future[Option[T]] = {
    if (n <= 0) Future.failed(new RuntimeException("Exceeded number of allowed retries"))
    else f().recoverWith { case originalError => notifyFailure(originalError); retry(f, notifyFailure, n - 1) }
  }

尾递归更新:Future的本质是异步的,所以除非你想等待结果,我不太明白它可以将其设为@tailrec,因为您必须在回调中使用递归。

还有实用说明:如果你知道它总是~10次重试,我就不会害怕递归。

关于具有 Future 返回类型的 Scala 递归函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40177970/

相关文章:

multithreading - Erlang BEAM 机器的减少

java - 结合 Java Swing 和 Java3D : performance problems with concurrency

c# - 将文本绘制到png文件上的性能方法?

java - 如何从每个线程的数组中读取唯一元素?

scala - 错误 : expected class or object definition

java - Scala StackOverflowError 而 Java 可以处理它

scala - 如何使用 Option[String] 按字母顺序对案例类进行排序而忽略 None 的?

scala - Akka 匿名 Actor 可以访问 self 吗?

go - 如何从多个 goroutine 写入同一个 channel

List.sum 自定义类