Allow retrying based on the "cause" exception
jeremyhaile opened this issue · 5 comments
Sometimes APIs wrap exceptions so that the top-level exception by itself isn't enough to determine whether or not to retry the code. However, the cause
exception could be used to determine that the code should be retried.
Currently retriable only allows retrying based on the raised exception, and doesn't provide a way to examine the caused exception.
Here is an example. In this case, we want to retry based on the RootCauseError
, but since the API we're using actually raises DemoError
, the code block doesn't get retried.
class RootCauseError < StandardError; end
class DemoError < StandardError; end
begin
i = 0
Retriable.retriable on: [RootCauseError] do
begin
puts "Try #{i += 1}..."
raise RootCauseError.new("BUT THIS IS THE CAUSE")
rescue => e
raise DemoError.new("RETRIABLE ONLY LOOKS AT THIS")
end
end
rescue => e
puts "Raised error: #{e.inspect}"
puts "Cause error: #{e.cause.inspect}"
end
Two ideas for solving this:
- Make retriable examine the cause of errors as well as the errors itself. This could either only go one level deep, or recurse...perhaps with a limit on recursion depth.
- Allow passing in a proc or method to the
on
option that would then be invoked with the error and would return true or false to determine if the error should be retried. This proc could then examine the error class and its cause, and would have the benefit of also supporting lots of advanced cases that are not possible right now.
Sorry I never replied to this ticket. I wanted to think about solutions for this and see if other users had similar issues. I haven't come to any conclusions, but wanted to comment to let you know I've read this issue.
you can sort of do this with a regex in the :on
parameter? often the "cause" gets stringified into the message of the actually raised parameter - that's a common pattern i've seen with Faraday
, for instance.
other than that i don't see any way to deal with the example posted; Retriable
can't reach into the block and figure out that someone rescue
d one exception and chose to raise a different type of exception.
re-reading my comment, i actually had no idea about the Exception#cause
feature in ruby 2.1. This issue makes a lot more sense to me now and seems like it might be worth implementing, though it will require some hackery depending on the ruby version.
It would be nice if the on
accepted a block and retry only if the result of the block is true
@rafaelsales i think that would be pretty straightforward to implement if you wanted to try to open a PR, though i'm not sure it's that relevant to this issue