我正在 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/