cats-effect
cats-effect copied to clipboard
Implement `Retry` functionality
trafficstars
The PR is influenced by #3135.
In my opinion, Retry must carry the error type. That way, we can implement retry functionality on top of the Handle from the cats-mtl.
I also decided to keep the name (perhaps the 'description' fits better?) around. That way, toString provides enough details to understand the retry strategy:
val policy = Retry
.exponentialBackoff[IO, Throwable](1.second)
.withCappedDelay(2.seconds)
.withMaxRetries(10)
println(policy)
// MaxRetries(CapDelay(Backoff(baseDelay=1 second, multiplier=Const(2.0), randomizationFactor=0.5), cap=2 seconds), max=5)
Usage
Retry on all errors
val policy = Retry
.exponentialBackoff[IO, Throwable](1.second)
.withMaxRetries(10)
// retries 10 times at most using an exponential backoff strategy
IO.raiseError(new RuntimeException("oops")).retry(policy)
Retry on some errors (e.g. TimeoutException)
val policy = Retry
.exponentialBackoff[IO, Throwable](1.second)
.withMaxRetries(10)
.withErrorMatcher(Retry.ErrorMatcher[IO, Throwable].only[TimeoutException])
// retries 10 times at most using an exponential backoff strategy
IO.raiseError(new TimeoutException("timeout")).retry(policy)
// gives up immediately
IO.raiseError(new RuntimeException("oops")).retry(policy)
Retry on all errors except the TimeoutException
val policy = Retry
.exponentialBackoff[IO, Throwable](1.second)
.withMaxRetries(10)
.withErrorMatcher(Retry.ErrorMatcher[IO, Throwable].except[TimeoutException])
// retries 10 times at most using an exponential backoff strategy
IO.raiseError(new RuntimeException("oops")).retry(policy)
// gives up immediately
IO.raiseError(new TimeoutException("timeout")).retry(policy)
A few points to discuss:
- A confusion between
withMaxDelay,withCappedDelay,withMaxCumulativeDelay. Even though I provided the documentation with examples, these three methods are confusing. Can we find better names? - Is my implementation of the exponential backoff correct?