Skip to content

Commit 108b51a

Browse files
osyoyutaketo1113
authored andcommitted
Replace Timeout.timeout with TCPSocket.open(open_timeout:) when available
This patch replaces the implementation of #open_timeout from Timeout.timeout from the builtin timeout in TCPSocket.open, which was introduced in Ruby 3.5 (https://bugs.ruby-lang.org/issues/21347). The builtin timeout in TCPSocket.open is better in several ways than Timeout.timeout. It does not rely on a separate Ruby Thread for monitoring Timeout (which is what the timeout library internally does). Furthermore, it is compatible with Ractors, as opposed to Timeout.timeout (it internally uses Thread::Mutex which can not be used in non-main Ractors). This change allows the following code to work. require 'net/http' Ractor.new { uri = URI('http://example.com/') http = Net::HTTP.new(uri.host, uri.port) http.open_timeout = 1 http.get(uri.path) }.value In Ruby <3.5 environments where `TCPSocket.open` does not have the `open_timeout` option, I have kept the behavior unchanged. net/http will use `Timeout.timeout { TCPSocket.open }`.
1 parent 58685b7 commit 108b51a

File tree

1 file changed

+15
-7
lines changed

1 file changed

+15
-7
lines changed

lib/net/http.rb

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,14 +1672,22 @@ def connect
16721672
end
16731673

16741674
debug "opening connection to #{conn_addr}:#{conn_port}..."
1675-
s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
1676-
begin
1677-
TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
1678-
rescue => e
1679-
raise e, "Failed to open TCP connection to " +
1680-
"#{conn_addr}:#{conn_port} (#{e.message})"
1675+
begin
1676+
s = begin
1677+
# Use built-in timeout in TCPSocket.open if available
1678+
TCPSocket.open(conn_addr, conn_port, @local_host, @local_port, open_timeout: @open_timeout)
1679+
rescue ArgumentError => e
1680+
raise if !e.message.include?('unknown keyword: :open_timeout')
1681+
# Fallback to Timeout.timeout if TCPSocket.open does not support open_timeout
1682+
Timeout.timeout(@open_timeout, Net::OpenTimeout) {
1683+
TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
1684+
}
16811685
end
1682-
}
1686+
rescue => e
1687+
e = Net::OpenTimeout.new(e) if e.is_a?(Errno::ETIMEDOUT) # for compatibility with previous versions
1688+
raise e, "Failed to open TCP connection to " +
1689+
"#{conn_addr}:#{conn_port} (#{e.message})"
1690+
end
16831691
s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
16841692
debug "opened"
16851693
if use_ssl?

0 commit comments

Comments
 (0)