-
Notifications
You must be signed in to change notification settings - Fork 984
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
Distinguish TimeoutErrors for open and read timeouts #718
Comments
Hi @coberlin I believe this might be a nice addition, I'm just scared about backwards compatibility. |
The rack_adapter might be the wrong place for this feature. I think Rack applications don't necessarily distinguish between open and read timeouts. Perhaps this feature would work in the HTTPClient adapter or other adapters? From adapter/httpclient.rb:
::HTTPClient::TimeoutError has 3 subclasses ConnectTimeoutError, ReceiveTimeoutError, SendTimeoutError, see e.g http://www.rubydoc.info/gems/httpclient/2.1.5.2/HTTPClient/TimeoutError Faraday has Faraday::Error::ConnectionFailed already. Is that appropriate for ConnectTimeoutError? Faraday::Error::TimeoutError could be subclassed into Faraday::Error::ReceiveTimeoutError and Faraday::Error::SendTimeoutError. |
This makes sense, but it wouldn't be backwards compatible. We have to keep in mind that people are already catching
Next step is to go into each adapter and map the adapter exceptions accordingly. E.g. for the HTTPClient:
Finally, tests should be added where possible :) |
Hey guys. We had this discussion a "little" time ago (#324). I'm giving it another try (https://github.com/mistersourcerer/faraday/tree/718_mrsrcr_timeout-wrapping-2nd-chance), will try and open a new PR as soon as I have some progress on it. |
Hi @mistersourcerer, thanks for the nudge, I was totally unaware that discussion took place. |
Hey @iMacTia. If I remember correctly, we didn't manage to solve the situation back then. But I'm not sure exactly why. Right now, the tests for EMSynchrony are failing on Travis, but not locally. Trying to figure it out. I'm thinking even on open an "early" PR so maybe we can discuss this. And your explanation is crystal clear, seems the perfect way to go with it. Thanks for the awesome work on this, man. |
Thank you @mistersourcerer! RE your changes: I'm not really sure of what happened, but I see @mislav finally merged your changes here: f73d13e So rejoice, |
Thanks for working on this @mistersourcerer! Looking at your commit here, I wonder if for backwards compatibility, we need 2 new subclasses: |
There appears to be some confusion around this issue. |
Follow-up in my previous comment. Basically, we're currently raising a On one side I understand that would be closer to reality, but if I analyse the issue from an implementation point of view, I find it hard to justify this change. Making the open timeout a sub-category of We need to:
@coberlin @erik-escobedo @mislav @mistersourcerer would like to hear your thoughts after considering the above 😄 |
Going with |
That's OK, once we decide we'll standardise all adapters to the same behaviour (in v1.0 obviously, as this will be backward incompatible) |
Throwing a use-case into the ring: At work we've been suffering from some Open Timeouts due to Nginx + Kubernetes failing to route to hanging pods (or something). Anyway, NetHTTP used to throw OpenTimeout and ReadTimeout errors, and that was really handy for us debugging which was which. Now we've switched to Typhoeus we sadly have all timeouts munged together, and it's tough for us to tell if our work on the nginx + kuber problems have been improved, or if we're just now successfully making more requests to an increasingly struggling system. Either way the number of timeouts are about the same, and without getting them separated we're kinda stuck guessing. I don't think just adding |
@philsturgeon and what about the other proposed solution, would that help as well? Open timeout -> That should be the behaviour on all adapters, but unfortunately some are not behaving as expected (i.e. Typhoeus) |
I feel like those are different things. ConnectionFailed seems like "I have no idea how to talk to this server", like an invalid DNS/IP etc. OpenTimeout is "I know where this server is im just waiting for it to do a thing" |
I disagree with that, I'd rather say: Open Timeout: I'm trying to contact the server, but I can't reach it (Note: connection not established or "opened" yet). A faulty firewall/proxy/load_balancer are just simple examples of how you might get an open timeout, but in all this cases the connection to the server has not started yet. That's the most important bit for me. "ConnectionFailed" to me simply means: I couldn't connect to the server. And it perfectly suits these cases. If you still think that a specific Faraday::OpenTimeoutError should exist, then I'd suggest that to inherit from Does it make sense? I would like to find a solution that fits everyone |
I accept your more accurate definitions for open timeout but I come to a different conclusion. You consider open timeout to be considered a connection failure as the amount of time you're wiling to wait for that connection is considered part of the connection. "Failed to make a connection in 5s" certainly makes sense if you explain it like that, but that's not how a lot of people think. For many, open timeout just means it has not happened yet. That makes it less of a definitive statement than most connection failures, which is "The server is down" or "This DNS is garbage". I suppose it doesn't much matter, as connection failures and open timeouts should both be retried, here as a read timeout might be considered grounds to back off? |
I agree, we can argue as much as we want on the reading one can apply to it, but the practicality of my point is what you said as well: If you get an Open Timeout it means you can retry the request, if you get a Read Timeout it means you have to be VERY careful as your request might have been process (entirely or partially). Coincidentally, the practical meaning of an open timeout matches the one of a failed connection, hence I would make it inherit from there. Today people are catching I understand (and agree) from a semantic point of view though that an OpenTimeout is just another type of Timeout. But hey, what if we call it |
There would be some confusion around |
Good point 😞 |
Call it |
Sounds good to me 👍! |
@iMacTia Is anyone working on this change? I don't mind taking this up for v2.0. |
Hi @ragav0102, thanks for the support! We'd definitely appreciate the help, but we don't have a plan yet for v2.0 so I can't tell when it will be released, so your changes may need to wait months before they can be used. If you need this in one of your projects, then that's probably not feasible. |
Got it! |
The versions of each of these had fallen a reasonable way behind mainline, which could cause issues when trying to depend on this code in more up-to-date codebases. There were 2 tests that I updated to make them more robust. The timeout one I made the queries explicit that were being mocked. There was another test that only worked up to the year 2020, so updating that to work until the year 3000. The newer versions of Faraday now use a ConnectionFailed error to indicate a timeout when opening the connection (lostisland/faraday#718), so updated accordingly. Restforce 5 requires ruby 2.5, so updated that requirement as well. Also updated the tests to point to the latest version of the API at time of writing.
Hi, I've a dumb question: I think it makes sense that read timeout should raise |
In faraday/adapter/rack.rb, TimeoutError is raised for both open and read timeouts:
According to https://stackoverflow.com/questions/10322283/what-is-timeout-and-open-timeout-in-faraday, open_timeout is for the tcp connection and timeout is for the response read.
It would be nice to have separate exception types for these timeouts. Then we could determine whether or not to retry the request. Does adding something like Faraday::Error::OpenTimeoutError and Faraday::Error::ResponseTimeoutError and using those here make sense?
The text was updated successfully, but these errors were encountered: