Skip to content

Instantly share code, notes, and snippets.

@kenoir
Created September 9, 2019 13:58
Show Gist options
  • Save kenoir/fb577017dfbb2c51539e9265320b29f5 to your computer and use it in GitHub Desktop.
Save kenoir/fb577017dfbb2c51539e9265320b29f5 to your computer and use it in GitHub Desktop.
import uk.ac.wellcome.storage.RetryableError
import scala.util.Random
import scala.annotation.tailrec
object RetryOps {
implicit class Retry[In, Out, Error](f: In => Either[Error, Out]) {
def retry(maxAttempts: Int = 1): In => Either[Error, Out] =
(in: In) => retryInternal(maxAttempts)(in)
@tailrec
private def retryInternal(remainingAttempts: Int)(in: In): Either[Error, Out] =
f(in) match {
case Right(out) => Right(out)
// We can't use `Left(err: RetryableError)` because
// the compiler needs to know that Left(err) in
// the if branch is an instance of Error.
//
// Even though we know that err is both an Error and
// a RetryableError (because it comes from f(in)),
// the compiler can't see that.
case Left(err) if err.isInstanceOf[RetryableError] =>
if (remainingAttempts == 1) {
Left(err)
} else {
retryInternal(remainingAttempts - 1)(in)
}
case Left(err) => Left(err)
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment