Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import Retry.{LazyLogging, Recovery}
- import Retry.Recovery.RecoverySettings
- import rx.lang.scala.Observable
- import scala.annotation.tailrec
- import scala.concurrent.{ExecutionContext, Future}
- import scala.util.Try
- object Retry {
- trait Recovery {
- this: LazyLogging =>
- trait RecoverableLike[T[_]] {
- import RecoverableLike._
- def recoverWith[R](t: => T[R], f: RecoveryFun[T, R]): T[R]
- }
- object RecoverableLike {
- type RecoveryFun[T[_], R] = PartialFunction[Throwable, T[R]]
- def apply[T[_]: RecoverableLike, R]: RecoverableLike[T] = implicitly[RecoverableLike[T]]
- implicit def recoverableObservable: RecoverableLike[Observable] = new RecoverableLike[Observable] {
- override def recoverWith[T](t: => Observable[T], f: RecoveryFun[Observable, T]): Observable[T] =
- t.onErrorResumeNext(f)
- }
- implicit def recoverableFuture(implicit ec: ExecutionContext): RecoverableLike[Future] = new RecoverableLike[Future] {
- override def recoverWith[T](t: => Future[T], f: RecoveryFun[Future, T]): Future[T] =
- t.recoverWith(f)
- }
- implicit def recoverableTry: RecoverableLike[Try] = new RecoverableLike[Try] {
- override def recoverWith[T](t: => Try[T], f: RecoveryFun[Try, T]): Try[T] =
- t.recoverWith(f)
- }
- type Supplier[T] = T
- implicit def recoverableSupplier[T]: RecoverableLike[Supplier] = new RecoverableLike[Supplier] {
- override def recoverWith[T](t: => Supplier[T], f: RecoveryFun[Supplier, T]): Supplier[T] = {
- recoverSupplier(t, f)
- }
- }
- private def recoverSupplier[T](supplier: => Supplier[T], recovery: RecoveryFun[Supplier, T]): Supplier[T] = {
- (Try {
- supplier
- } recover {
- recovery
- }).get
- }
- }
- def retry[T[_] : RecoverableLike, R](msg: String)(f: => T[R])(implicit recoverySettings: RecoverySettings): T[R] = {
- retryRecursively(msg, 1, f)
- }
- @tailrec
- private def retryRecursively[T[_] : RecoverableLike, R](msg: String, retry: Int, f: => T[R])
- (implicit recoverySettings: RecoverySettings): T[R] = {
- if (retry > recoverySettings.retries) f
- else retryRecursively(msg, retry + 1,
- RecoverableLike[T, R].recoverWith(f, {
- case t: Throwable =>
- logger.error(s"$msg (retry $retry of ${recoverySettings.retries})", t)
- f
- }))
- }
- }
- object Recovery {
- case class RecoverySettings(delay: Int, retries: Int)
- }
- trait LazyLogging {
- object logger {
- def error(s: String, t: Throwable) = {
- println(s)
- t.printStackTrace()
- }
- }
- }
- }
- object Test extends App with Recovery with LazyLogging {
- implicit val recoverySettings: RecoverySettings = RecoverySettings(100, 4)
- import scala.concurrent.ExecutionContext.Implicits._
- var i = 0
- def f(): Int = {
- i += 1
- if(i < 3) throw new RuntimeException
- else 4
- }
- retry("Failed to get int") (Try(f())).foreach(println)
- Thread.sleep(1000)
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement