Skip to content

Commit 6bfee9b

Browse files
osyoyutaketo1113
authored andcommitted
Remember if TCPSocket impl supports open_timeout
For open_timeout support detection, the previous implementation relied on an ArgumentError being raised and then rescued. In Ruby, rescue is a rather expensive operation and should be avoided when possible. This patch reduces the number of begin-rescues by remembering if the TCPSocket implementation supports open_timeout.
1 parent 9a10a36 commit 6bfee9b

File tree

1 file changed

+25
-10
lines changed

1 file changed

+25
-10
lines changed

lib/net/http.rb

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,6 +1179,7 @@ def initialize(address, port = nil) # :nodoc:
11791179
@debug_output = options[:debug_output]
11801180
@response_body_encoding = options[:response_body_encoding]
11811181
@ignore_eof = options[:ignore_eof]
1182+
@tcpsocket_supports_open_timeout = nil
11821183

11831184
@proxy_from_env = false
11841185
@proxy_uri = nil
@@ -1673,16 +1674,30 @@ def connect
16731674

16741675
debug "opening connection to #{conn_addr}:#{conn_port}..."
16751676
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') || e.message.include?('wrong number of arguments (given 5, expected 2..4)'))
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-
}
1685-
end
1677+
s =
1678+
case @tcpsocket_supports_open_timeout
1679+
when nil, true
1680+
begin
1681+
# Use built-in timeout in TCPSocket.open if available
1682+
sock = TCPSocket.open(conn_addr, conn_port, @local_host, @local_port, open_timeout: @open_timeout)
1683+
@tcpsocket_supports_open_timeout = true
1684+
sock
1685+
rescue ArgumentError => e
1686+
raise if !(e.message.include?('unknown keyword: :open_timeout') || e.message.include?('wrong number of arguments (given 5, expected 2..4)'))
1687+
@tcpsocket_supports_open_timeout = false
1688+
1689+
# Fallback to Timeout.timeout if TCPSocket.open does not support open_timeout
1690+
Timeout.timeout(@open_timeout, Net::OpenTimeout) {
1691+
TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
1692+
}
1693+
end
1694+
when false
1695+
# The current Ruby is known to not support TCPSocket(open_timeout:).
1696+
# Directly fall back to Timeout.timeout to avoid performance penalty incured by rescue.
1697+
Timeout.timeout(@open_timeout, Net::OpenTimeout) {
1698+
TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
1699+
}
1700+
end
16861701
rescue => e
16871702
e = Net::OpenTimeout.new(e) if e.is_a?(Errno::ETIMEDOUT) # for compatibility with previous versions
16881703
raise e, "Failed to open TCP connection to " +

0 commit comments

Comments
 (0)