http icon indicating copy to clipboard operation
http copied to clipboard

Remove Timeout.timeout

Open Gargron opened this issue 6 years ago • 5 comments

Timeout.timeout is not thread-safe and can interrupt any line, anywhere. Using native timeouts on the system level, or using IO.select is recommended for sockets. HTTP.rb already uses the right thing for read/write timeouts, but not connect.

I was able to use a better timeout for DNS resolving by overriding the socket class and using Resolv, however, that still leaves the opening of the actual socket, and the SSL handshake.

What can I do to avoid Timeout.timeout while not exposing myself to unreachable hosts taking infinitely long during the connect phase? I need to use HTTP.rb in a connection pool.

Gargron avatar Mar 24 '19 21:03 Gargron

This is the sort of problem I was trying to address in Socketry, which supports multiple different types of resolvers for particularly these sorts of problematic cases:

https://github.com/socketry/socketry/tree/master/lib/socketry/resolver

The problem is Resolv is kind of bad, and will be missing a lot of the functionality in the system resolver, so it's important to have both.

There was a WIP PR to switch all of the I/O in the library over to Socketry, but I never completed it: https://github.com/httprb/http/pull/377

tarcieri avatar Mar 24 '19 22:03 tarcieri

Alright, I have attempted to replace TCPSocket.open with something that calls Socket#connect_nonblocking with IO.select instead, but honestly, I am way out of my depth with this stuff, could you please take a look at this snippet:

https://github.com/tootsuite/mastodon/blob/43269ce9dbc3a93bd5bad4bf75d6e1e9ddfc1980/app/lib/request.rb#L177-L225

And tell me if this is complete garbage or not? It seems to work, and I seem to be able to both get normal non-timing out responses normally, and it seems to time out after 5 seconds on blackhole.webpagetest.org as it should (Mind that I monkey-patch the HTTP::Timeout::PerOperation class to remove Timeout.timeout call as well)

Gargron avatar Mar 24 '19 23:03 Gargron

That's the basic idea, yes. See also:

https://github.com/socketry/socketry/blob/master/lib/socketry/resolver/resolv.rb

As an alternative to a wholesale move to Socketry, instead http.rb could just use its resolvers, and then it would be possible to do something like HTTP.dns_resolver(Socketry::Resolver::Resolv).

tarcieri avatar Mar 24 '19 23:03 tarcieri

Did you guys comes to any stable conclusion on this?

uberllama avatar May 24 '19 14:05 uberllama

Did you guys comes to any stable conclusion on this?

My own solution lives in tootsuite/mastodon#10353

Gargron avatar May 24 '19 14:05 Gargron