Feature #19965
closedMake the name resolution interruptible
Description
Problem¶
Currently, Ruby name resolution is not interruptible.
$ cat /etc/resolv.conf
nameserver 198.51.100.1
$ ./local/bin/ruby -rsocket -e 'Addrinfo.getaddrinfo("www.ruby-lang.org", 80)'
^C^C^C^C
If you set a non-responsive IP as the nameserver, you cannot stop Addrinfo.getaddrinfo
by pressing Ctrl+C. Note that Timeout.timeout
does not work either.
This is because there is no way to cancel getaddrinfo(3)
.
Proposal¶
I wrote a patch to make getaddrinfo(3)
work in a separate pthread.
https://github.com/ruby/ruby/pull/8695
Whenever it needs name resolution, it creates a worker pthread, and executes getaddrinfo(3)
in it.
The caller thread waits for the worker to complete.
When an interrupt occurs, the caller thread leaves stop waiting and leaves the worker pthread.
The detached worker pthread will exit after getaddrinfo(3)
completes (or name resolution times out).
Evaluation¶
By applying this patch, name resolution is now interruptible.
$ ./local/bin/ruby -rsocket -e 'pp Addrinfo.getaddrinfo("www.ruby-lang.org", 80)'
^C-e:1:in `getaddrinfo': Interrupt
from -e:1:in `<main>'
As a drawback, name resolution performance will be degraded.
10000.times { Addrinfo.getaddrinfo("www.ruby-lang.org", 80) }
# Before patch: 2.3 sec.
# After ptach: 3.0 sec.
However, I think that name resolution is typically short enough for the application's runtime. For example, the difference is small for the performance of URI.open
.
100.times { URI.open("https://www.ruby-lang.org").read }
# Before patch: 3.36 sec.
# After ptach: 3.40 sec.
Alternative approaches¶
I proposed using c-ares to resolve this issue (#19430). However, there was an opinion that it would be a problem that c-ares does not respect the platform-dependent own name resolution.
Room for improvement¶
- Currently, this patch works only when pthread is available.
- It might be possible to force to stop the worker threads by using
pthread_cancel
. However,pthread_cancel
withgetaddrinfo(3)
seems still premature; there seems to be a bug in glibc until recently: https://bugzilla.redhat.com/show_bug.cgi?id=1405071 https://sourceware.org/bugzilla/show_bug.cgi?id=20975 - It would be more efficient to pool worker pthreads instead of creating them each time.