Issue #16476 has been updated by jeremyevans0 (Jeremy Evans).


ioquatix (Samuel Williams) wrote in #note-12:
> Adding timeouts as arguments is not particularly useful either. It's not particularly easy to compose timeouts or use a single timeout for multiple operations, and it makes the underlying implementation more complex.

One way around this is to use a deadline instead of a timeout:

```ruby
# or something based on Process.clock_gettime
deadline = Time.now + 5

Addrinfo.getaddrinfo("www.ruby-lang.org", "http", deadline: deadline)
Addrinfo.getaddrinfo("docs.ruby-lang.org", "http", deadline: deadline)
Addrinfo.getaddrinfo("bugs.ruby-lang.org", "http", deadline: deadline)
```

I think this approach is much better than a `Timeout.timeout` block.  For one, `Timeout.timeout` requires the use of `Thread#raise` and results in less deterministic behavior. Additionally, a deadline option can potentially use a different approach than raising an exception, similar to `IO#read_nonblock`.

----------------------------------------
Feature #16476: Socket.getaddrinfo cannot be interrupted by Timeout.timeout
https://bugs.ruby-lang.org/issues/16476#change-88934

* Author: kirs (Kir Shatrov)
* Status: Closed
* Priority: Normal
* Assignee: Glass_saga (Masaki Matsushita)
* Target version: 3.0
----------------------------------------
It seems like the blocking syscall done by `Socket.getaddrinfo` blocks Ruby VM in a way that Timeout.timeout has no effect.
See reproduction steps in getaddrinfo_interrupt.rb (https://gist.github.com/kirs/00c02ef92e0418578135fe0a6cbd3d7d). This affects all modern Ruby versions, including the latest 2.7.0.

Combined with default 10s resolv timeout on many Linux systems, this can have a very noticeable effect on production Ruby apps being not resilient to slow DNS resolutions, and being unable to fail fast even with `Timeout.timeout`.

While https://bugs.ruby-lang.org/issues/15553 improves the situation for `Addrinfo.getaddrinfo`, `Socket.getaddrinfo` is still blocking the VM and Timeout has no effect.

I'd like to discuss what could be done to make that call non-blocking for threads in Ruby VM.

**UPD:** looking closer, I can see that `Socket.getaddrinfo("www.ruby-lang.org", "http")` and `Addrinfo.getaddrinfo("www.ruby-lang.org", "http")` call non-interruptible `getaddrinfo`, while `Addrinfo.getaddrinfo("www.ruby-lang.org", "http", timeout: 10)` calls `getaddrinfo_a`, which is interruptible:

``` ruby
# interrupts as expected
Timeout.timeout(1) do
  Addrinfo.getaddrinfo("www.ruby-lang.org", "http", timeout: 10)
end
```

I'd maybe suggest that we try to *always* use `getaddrinfo_a` when it's available, including in `Socket.getaddrinfo`. What downsides that would have?
I'd be happy to work on a patch.



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>