try {
val res = retry(...) {
...
}
} catch {
case RetryException(es) => ...
}
じゃなく
val res = retry(...) {
...
} `catch` {
case es =>
}
と書けるように魔改造してみた
object RetryUtil { | |
import scala.util.control.Exception.allCatch | |
case class RetryResult[T](e: Either[List[Throwable], T]) { | |
def `catch`(f: List[Throwable] => T): T = e match { | |
case Right(r) => r | |
case Left(l) => f(l) | |
} | |
} | |
def retry[T](retryLimit: Int)(f: => T): RetryResult[T] = | |
retry(retryLimit, 0, classOf[Throwable])(f) | |
def retry[T](retryLimit: Int, retryInterval: Int)(f: => T): RetryResult[T] = | |
retry(retryLimit, retryInterval, classOf[Throwable])(f) | |
def retry[T](retryLimit: Int, catchExceptionClasses: Class[_]*)(f: => T): RetryResult[T] = | |
retry(retryLimit, 0, e => catchExceptionClasses.exists(_.isAssignableFrom(e.getClass)))(f) | |
def retry[T](retryLimit: Int, shouldCatch: Throwable => Boolean)(f: => T): RetryResult[T] = | |
retry(retryLimit, 0, shouldCatch)(f) | |
def retry[T](retryLimit: Int, retryInterval: Int, catchExceptionClasses: Class[_]*)(f: => T): RetryResult[T] = | |
retry(retryLimit, retryInterval, e => catchExceptionClasses.exists(_.isAssignableFrom(e.getClass)))(f) | |
def retry[T](retryLimit: Int, retryInterval: Int, shouldCatch: Throwable => Boolean)(f: => T): RetryResult[T] = { | |
@annotation.tailrec | |
def retry0(errors: List[Throwable], f: => T): RetryResult[T] = { | |
allCatch.either(f) match { | |
case Right(r) => RetryResult(Right(r)) | |
case Left(e) => | |
if (shouldCatch(e)) { | |
if (errors.size < retryLimit - 1) { | |
Thread.sleep(retryInterval) | |
retry0(e :: errors, f) | |
} else { | |
RetryResult(Left(e :: errors)) | |
} | |
} else throw e | |
} | |
} | |
retry0(Nil, f) | |
} | |
} |