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) | |
| } | |
| } |