cats-retry
cats-retry copied to clipboard
Allow the action to be redefined after errors
Hi! We have a case where our action should not just be repeated on retries, but rather called in a slightly different way, based on the exact error received.
It could look like this (roughly):
case class VersionMismatch(v: Int) extends Throwable
def action(i: Int): IO[A] = ???
//ignored `isWorthRetrying`/`policy` parameters as they're irrelevant
//action: I => F[A]
//onError: E => F[Option[I]]
action.retryingOnSomeErrors(onError = {
case VersionMismatch(v) =>
logger.debug("Version mismatch, retrying...").as(v.some)
case e =>
logger.debug(s"Not retrying: $e").as(none)
}).apply(0) //initial value of `i`
As an alternative, the onError
function could return the action to be used for retrying - this would probably be more flexible:
//action: F[A]
//onError: E => F[Option[F[A]]
action(0).retryingOnSomeErrors(onError = {
case VersionMismatch(v) =>
logger.debug("Version mismatch, retrying...").as(action(v).some)
case e =>
logger.debug(s"Not retrying: $e").as(none)
}
Our current workaround is creating a Ref
to store the input, and getting it within the retryable action - but it's not a concurrent scenario and Ref
seems like overkill (whereas underneath it would be relatively simple recursion).
I'm in two minds on this one. It feels a little bit of a niche use case to me. I'd only add support for this if we can ensure we don't make life more difficult for people who don't need this feature.
If we're going to do it, I prefer the latter approach you suggested.
Hi, I'm aware it's been a while, but is there any implementation on this? Because I need something like this.
I'm not aware of any. I would suggest that you use a Ref for now. IIRC this would look roughly like this:
def action(i: Int): IO[A] = ???
// 0 - initial value used as input to `action`
Ref[IO].of(0).flatMap { ref =>
ref.get.flatMap(action).retryingOnSomeErrors(
// skipped here: isWorthRetrying, policy
onError = e => logger.error(e) *> ref.set(i + 1) //calculating next input as `i + 1`
)
}
@kubukoz thank you very much for taking the time to respond, and that solution is pretty neat, I'll try it.