Skip to content

Instantly share code, notes, and snippets.

@ahoy-jon
Last active July 31, 2017 06:32
Show Gist options
  • Save ahoy-jon/3c145850fefc0b2579d9d0e101e3a599 to your computer and use it in GitHub Desktop.
Save ahoy-jon/3c145850fefc0b2579d9d0e101e3a599 to your computer and use it in GitHub Desktop.
object TryOps {
import scala.util.{Failure, Try, Success}
import scala.annotation.tailrec
/*can be used as :
(Try {
HTTP.get(".....")
}).retryGet(3)
*/
@tailrec
def lowRetry[T](f:() => Try[T])(n:Int)(ref:Option[Int] = None, maxAttempts:Option[Int] = None):Try[T] = {
require(n > 0)
if(n == 1){
maxAttempts match {
case Some(nMax) => f().recoverWith({case e => Failure(new Exception(s"max retry $nMax",e))})
case _ => f()
}
} else {
val t = f()
val nref = System.identityHashCode(t)
if(ref.contains(nref)) {
t.recoverWith({case e => Failure(new Exception("can't retry eager try", e))})
} else {
t match {
case _:Success[T] => t
case Failure(e) => lowRetry(f)(n - 1)(Some(nref), maxAttempts orElse Some(n))
}
}
}
}
implicit class TryOps[T](t: => Try[T]) {
def retry(n: Int): Try[T] = lowRetry(() => t)(n)()
}
def retry[T](t: => Try[T])(n: Int): Try[T] = TryOps(t).retry(n)
def main(args: Array[String]): Unit = {
var i = 0
val v = Try {
i = i + 1
if (i == 1) {
println("first try")
throw new Exception("0")
} else {
println("second try")
2
}
}.retry(3)
assert(v == Try(2))
assert(i == 2)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment