cats-effect icon indicating copy to clipboard operation
cats-effect copied to clipboard

Implement `Retry` functionality

Open iRevive opened this issue 1 year ago • 5 comments
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:

  1. A confusion between withMaxDelay, withCappedDelay, withMaxCumulativeDelay. Even though I provided the documentation with examples, these three methods are confusing. Can we find better names?
  2. Is my implementation of the exponential backoff correct?

iRevive avatar Jul 26 '24 17:07 iRevive