diff --git a/modules/core/shared/src/main/scala/retry/RetryPolicies.scala b/modules/core/shared/src/main/scala/retry/RetryPolicies.scala index 59e32aa..8c063a8 100644 --- a/modules/core/shared/src/main/scala/retry/RetryPolicies.scala +++ b/modules/core/shared/src/main/scala/retry/RetryPolicies.scala @@ -72,6 +72,16 @@ object RetryPolicies { show"limitRetries(maxRetries=$maxRetries)" ) + /** Retry up to maxRetries with fixed delay between retries + */ + def limitRetriesWithFixedDelay[M[_]: Applicative]( + maxRetries: Int, + delay: FiniteDuration + ): RetryPolicy[M] = + RetryPolicies + .limitRetries[M](maxRetries) + .join(RetryPolicies.constantDelay(delay)) + /** Delay(n) = Delay(n - 2) + Delay(n - 1) * * e.g. if `baseDelay` is 10 milliseconds, the delays before each retry will be diff --git a/modules/core/shared/src/test/scala/retry/RetryPoliciesSpec.scala b/modules/core/shared/src/test/scala/retry/RetryPoliciesSpec.scala index b4dfc5c..ba79f4d 100644 --- a/modules/core/shared/src/test/scala/retry/RetryPoliciesSpec.scala +++ b/modules/core/shared/src/test/scala/retry/RetryPoliciesSpec.scala @@ -49,6 +49,13 @@ class RetryPoliciesSpec extends AnyFlatSpec with Checkers { s"exponentialBackoff($baseDelay)" ) ), + for { + delay <- genFiniteDuration + maxRetries <- Gen.posNum[Int] + } yield LabelledRetryPolicy( + limitRetriesWithFixedDelay(maxRetries, delay), + s"limitRetriesWithFixedDelay($maxRetries, $delay)" + ), Gen .posNum[Int] .map(maxRetries => @@ -198,6 +205,22 @@ class RetryPoliciesSpec extends AnyFlatSpec with Checkers { } } + behavior of "limitRetriesWithFixedDelay" + + it should "always retry with the same delay or give up after maxRetries is reached" in check { + (status: RetryStatus) => + val limit = 500 + val verdict = + limitRetriesWithFixedDelay(limit, 1.millisecond).decideNextRetry( + status + ) + if (status.retriesSoFar < limit) { + verdict == PolicyDecision.DelayAndRetry(1.millisecond) + } else { + verdict == PolicyDecision.GiveUp + } + } + behavior of "limitRetriesByDelay" it should "give up if the underlying policy chooses a delay greater than the threshold" in {