Pierre Andrews 


Retry a fail-able block in Scala

I have seen a few implementations of this online, in particular Retrying with style, which is a two years old post and has a few things that bothered me:

  1. it's blocking, Futures where not in scala at the time,
  2. it uses mutable variables, which are not intrinsically bad in such a contained context; but my editor highlights them in red and I don't like having red bits in my code :D

I have thus created a new implementation available at this gist.

The idea is that you could have a block of code that fails for any kind of reasons which are non deterministic. For instance, a call to the DB could fail because the connection queue is full, or a request to a webservice could fail because the "internet is busy".

Instead of writting a loop and a lot of code relevant to the retry part, you can write a block wrapper in scala that will take care of everything in the background for you:

val myResult = retry(10) {
   ...
   makeWSCall()
   ...
}

This is what the little bit of code that I have put in this gist does. I won't copy all of it here as it's too long, but here are some comments on how it works:

Because the block returns a Future, the retries are executed asynchronously, hopefully not blocking your data flow. You can use the Future API to manipulate the value eventually returned:

myResult.map(_ * 2)

You can also use the built-in recovery methods of Future to deal with a failed result (too many retries):

val myResult = retry(10) {
   ...
   makeWSCall()
   ...
} recover {
  case t: Throwable => 0
}

The retry function also provides some advanced optional parameters:

val myResult = retry(10, Some(10 seconds fromNow)) {
   ...
   makeWSCall()
   ...
}
val myResult = retry(10, backoff = (r) => 100 milliseconds) {
   ...
   makeWSCall()
   ...
}