From 7cf5e1d8b453803a193db6f6db51c819c75ec51a Mon Sep 17 00:00:00 2001 From: svroonland Date: Wed, 30 Sep 2020 14:26:52 +0200 Subject: [PATCH] Add support for schedules with an environment requirement to Retry (#42) * Add support for schedules with an environment requirement * Fix --- .../scala/nl/vroste/rezilience/Retry.scala | 39 +++++++++++++++---- .../nl/vroste/rezilience/RetrySpec.scala | 2 +- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/rezilience/shared/src/main/scala/nl/vroste/rezilience/Retry.scala b/rezilience/shared/src/main/scala/nl/vroste/rezilience/Retry.scala index d2a63c60..e3131dcb 100644 --- a/rezilience/shared/src/main/scala/nl/vroste/rezilience/Retry.scala +++ b/rezilience/shared/src/main/scala/nl/vroste/rezilience/Retry.scala @@ -50,16 +50,41 @@ object Retry { zio.Schedule.recurWhile(pf.isDefinedAt) && schedule } - def make[E](schedule: Schedule[Any, E, Any]): ZManaged[Clock, Nothing, Retry[E]] = - ZManaged.environment[Clock].map(RetryImpl(_, schedule)) + /** + * Create a Retry from a ZIO Schedule + * @param schedule + * @tparam R + * @tparam E + * @return + */ + def make[R, E](schedule: Schedule[R, E, Any]): ZManaged[Clock with R, Nothing, Retry[E]] = + ZManaged.environment[Clock with R].map(RetryImpl(_, schedule)) + + /** + * Create a Retry policy with exponential backoff + * + * @param min Minimum retry backoff delay + * @param max Maximum retry backoff delay + * @param factor Factor with which delays increase + * @return + */ + def make( + min: Duration = 1.second, + max: Duration = 1.minute, + factor: Double = 2.0 + ): ZManaged[Clock, Nothing, Retry[Any]] = + ZManaged.environment[Clock].map(RetryImpl(_, Schedule.exponentialBackoff(min, max, factor))) - private case class RetryImpl[-E](clock: Clock, schedule: Schedule[Any, E, Any]) extends Retry[E] { + private case class RetryImpl[-E, ScheduleEnv]( + scheduleEnv: Clock with ScheduleEnv, + schedule: Schedule[ScheduleEnv, E, Any] + ) extends Retry[E] { override def apply[R, E1 <: E, A](f: ZIO[R, E1, A]): ZIO[R, E1, A] = - ZIO.environment[R].flatMap(env => f.provide(env).retry(schedule).provide(clock)) + ZIO.environment[R].flatMap(env => f.provide(env).retry(schedule).provide(scheduleEnv)) - override def widen[E2](pf: PartialFunction[E2, E]): Retry[E2] = RetryImpl[E2]( - clock, - (zio.Schedule.stop ||| schedule).contramap[Any, E2] { e2 => + override def widen[E2](pf: PartialFunction[E2, E]): Retry[E2] = RetryImpl[E2, ScheduleEnv]( + scheduleEnv, + (zio.Schedule.stop ||| schedule).contramap[ScheduleEnv, E2] { e2 => pf.andThen(Right.apply[E2, E](_)).applyOrElse(e2, Left.apply[E2, E](_)) } ) diff --git a/rezilience/shared/src/test/scala/nl/vroste/rezilience/RetrySpec.scala b/rezilience/shared/src/test/scala/nl/vroste/rezilience/RetrySpec.scala index 84a64364..7aa09585 100644 --- a/rezilience/shared/src/test/scala/nl/vroste/rezilience/RetrySpec.scala +++ b/rezilience/shared/src/test/scala/nl/vroste/rezilience/RetrySpec.scala @@ -11,7 +11,7 @@ object RetrySpec extends DefaultRunnableSpec { override def spec = suite("Retry")( testM("widen should not retry unmatched errors") { Retry - .make[Throwable](Retry.Schedule.exponentialBackoff(1.second, 2.seconds)) + .make(Retry.Schedule.exponentialBackoff(1.second, 2.seconds)) .map(_.widen(Policy.unwrap[Throwable])) .use { retry => for {