From: naruse@... Date: 2020-12-28T10:41:37+00:00 Subject: [ruby-core:101771] [Ruby master Feature#16476] Socket.getaddrinfo cannot be interrupted by Timeout.timeout Issue #16476 has been updated by naruse (Yui NARUSE). Dan0042 (Daniel DeLorme) wrote in #note-16: > naruse (Yui NARUSE) wrote in #note-15: > > 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. > > How common is it to need separate timeouts for all of these? I can easily imagine the resolv_timeout as being part of the connect_timeout (i.e. resolv+connect may not exceed connect_timeout). And at least in my experience I usually want a single "general timeout" for resolv+connect+write+read. For that reason I _really_ like Jeremy's suggestion of a single `deadline` argument. You can even have a single deadline for multiple http requests. This is really perfect for most uses cases that I'm familiar with. Both `Timeout.timeout` and `deadline` is not the essential problem of this topic. The topic this ticket handles is "getaddrinfo is not interruptable nor timeout ready". This is because getaddrinfo(3) doesn't have timeout, async, nor nonblocking API. This ticket intends to provide the underlying implementation of such feature. ---------------------------------------- Feature #16476: Socket.getaddrinfo cannot be interrupted by Timeout.timeout https://bugs.ruby-lang.org/issues/16476#change-89599 * 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: