Scala Recursive Function with Future Return Type
concurrency, scala
Solution
How about this?
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) }
}
Update on tail recursion: The nature of `Future` is asynchronous so unless you want to `await` for result, I do not quite see it being possible to make it `@tailrec` because you will have to use recursion in callback.
Also practical note: if you know it is always ~10 retries, I would not be afraid of recursion.
Problem
I am writing a recursive retry function in scala where I want to know if there was a runtime error with the future creation. If there is then future instantiation is retried. Imagine I have a database query function: ``` dbLookup(userId : UserId) : Option[UserName] = ??? ``` The retry would look something of the form: ``` 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 } } } ``` How can this future functionality be implemented and allow for tail recursion optimization? This function could be used to retry the database 10 times for a user if the execution context keeps throwing an exception when I try to create a Future: ``` val userNameAfterRetries = retry(() => Future{dbLookup("1234")}, (t) => system error (s"future creation error : $t"), 10) ``` Note: this is sort of possible with `Future.fallbackTo`, but unfortunately fallbackTo takes in a `Future[T]` rather than a `() => Future[T]`. This is important because using fallbackTo would result in retrying at least 1 extra times even if the first attempt was successful. Thank you in advance for your consideration and response.