-
Notifications
You must be signed in to change notification settings - Fork 981
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
retry middleware, exceptions
option as String does not match on exception sub-classes
#1330
Comments
exceptions
options as string does not match exception sub-classesexceptions
options as String does not match on exception sub-classes
exceptions
options as String does not match on exception sub-classesexceptions
option as String does not match on exception sub-classes
Thank you for raising this @jrochkind and for doing some good research. Although I think the latter solution ("the code would just have to turn the string into the actual class/module it represents before just using is_a? as normal") would be best, I believe the main purpose of the string option is to avoid cases where the Exception may not be initialised yet. This may particularly be an issue in Rails-like environments where there's heavy usage of autoloading. But that could be fixed with an extra check on the the module actually being defined, which I still think it's a better solution than reimplementing traversing the ancestors array as Ruby already does inside I'd welcome a PR attempting that and introducing test coverage to show both options can now check sub-classes as well 👍 |
Thanks for the response! I guess the way to turn a string like I'm not sure how to check if it's defined first... can't figure out a way to do that. I think maybe it'd have to be a rescue? Hmm something like: if ex.is_a? Module
error.is_a? ex
else
begin
error.class.to_s == Kernel.const_get(ex.to_s)
rescue NameError
end
end As I think about it more, the version with the "ancestors" check seems maybe simpler and preferable? Unless maybe there's a performance problem? One possible use case for the string version is avoiding problems when the class you want to mention is automatically reloaded per-request by Rails development-mode, so the module you captured at boot is no longer right? Not sure what use case(s) motivated the original feature, but you're right that it is possible for the class not to exist, so I guess backwards compatibility alone would say that should not raise if it doesn't currently. It doesn't look like there's currently any test for exceptions option as a string; but there is a basic test of the exceptions option. faraday/spec/faraday/request/retry_spec.rb Lines 30 to 34 in 506e97a
So seems straightforward to add an alternate with a string version; and maybe a test that a class name that doesn't exist doesn't raise, too? I'll try to find time to make and submit a PR next week. |
Using a rescue this can be pretty simple, but you still need to use unless ex.is_a?(Module)
# Use Object instead of Kernel, this is also what active support uses internally in `#constantize`
ex = Object.const_get(ex.to_s) rescue nil
# if the conversion fails, the error doesn't exist, so we can't possibly match it with anything
return false unless ex
end
# If you reach this point, `ex` MUST be a Module/Class
error.is_a?(ex)
If you prefer avoid using unless ex.is_a?(Module)
# if the conversion fails, the error doesn't exist, so we can't possibly match it with anything
return false unless Object.const_defined?(ex.to_s)
# Use Object instead of Kernel, this is also what active support uses internally in `#constantize`
ex = Object.const_get(ex.to_s)
end
# If you reach this point, `ex` MUST be a Module/Class
error.is_a?(ex) And the latter is much more performant (~4x) when it comes to missing constants:
That would be great! |
OK thanks for the tips! I'll see what I can do. (I definitely avoid the one-liner |
…ass name consistently Closes lostisland#1330
…ass name consistently Closes lostisland#1330
@jrochkind just a quick note that your PR was successfully merged in |
Ah, ok, thanks for the note! I will see about that maybe. Is there any general estimate of when 2.0 might drop, like even just is it "almost done" at this point, or "just beginning"? |
We've got a project board to track progress, most of the heavy-lifting is done. The only things left are a ticket about timeout errors (which I'm still not 100% sure to include in this major release) and other minor decorative changes. So I'd say we're close, though I'm always struggling for time. And just to be clear, I personally wouldn't push for back-porting the fix, I'm all for keeping it on v2.0 👍 |
Basic Info
Issue description
The
exceptions
option is documented to work as a module/class (egFaraday::Error
), or as a string (eg"Faraday::Error"
).If you pass it as the class object itself, it matches on all sub-classes. For instance, if you pass
Faraday::Error
, the retry will still happen if the exception raised wereFaraday::ConnectionFailed
orFaraday::TimeoutError
, as these are both sub-classes ofFaraday::Error
. This is exactly what a rubyist would expect; it's how similar APIs (including rubyrescue
itself) generally work.However, if you pass the argument instead as a string,
"Faraday::Error"
, it will only be considered matched if the exception raised is exactly aFaraday::Error
, not a sub-class likeFaraday::ConnectionFailed
orFaraday::TimeoutError
.This is unexpected, that passing a string changes semantics like this. Either it's a bug that String argument works differently (I think it probably is?); or it should be documented that it works differently.
We can see why it works how it works in the implementation here:
faraday/lib/faraday/request/retry.rb
Line 187 in 506e97a
If it is to work as expected, either that would need to be changed to something like
error.class.ancestors.collect(&:to_s).include?(ex.to_s)
, or the code would just have to turn the string into the actual class/module it represents before just usingis_a?
as normal.I could submit a PR if someone provides guidance as to preferred path.
The text was updated successfully, but these errors were encountered: