Suppose I\'ve got a function foo
that performs asynchronous computation and returns a Future
:
def foo(x: Int)(implicit ec: Executio
I'd probably do something like this:
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
is call-by-name since it itself could throw an exception rather than returning a failed Future. I keep the accumulated exceptions in a list, but I guess that's a taste-thing.