From: naruse@... Date: 2020-12-27T09:45:17+00:00 Subject: [ruby-core:101733] [Ruby master Feature#16476] Socket.getaddrinfo cannot be interrupted by Timeout.timeout Issue #16476 has been updated by naruse (Yui NARUSE). Target version changed from 3.0 to 3.1 Status changed from Closed to Open ioquatix (Samuel Williams) wrote in #note-12: > * I'm not convinced that getaddrinfo_a is a good idea, it has a user-space thread pool and the implementation doesn't seem great. https://github.com/ruby/ruby/commit/2038cc6cab6ceeffef3ec3a765c70ae684f829ed is reverted because of [Bug #17220]. > 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. In my experience timeout is important for web applications to return a response when a DNS resolution is too slow. It's a long requested series of improvements for HTTP client like read_timeout, connect_timeout, and write_timeout. resolv_timeout is the last piece of that. ---------------------------------------- Feature #16476: Socket.getaddrinfo cannot be interrupted by Timeout.timeout https://bugs.ruby-lang.org/issues/16476#change-89554 * Author: kirs (Kir Shatrov) * Status: Open * Priority: Normal * Assignee: Glass_saga (Masaki Matsushita) * Target version: 3.1 ---------------------------------------- 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: