ruby-changes:47916
From: naruse <ko1@a...>
Date: Tue, 26 Sep 2017 23:00:30 +0900 (JST)
Subject: [ruby-changes:47916] naruse:r60035 (trunk): Make retries for Net::HTTP configurable [Feature #10674]
naruse 2017-09-26 23:00:25 +0900 (Tue, 26 Sep 2017) New Revision: 60035 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=60035 Log: Make retries for Net::HTTP configurable [Feature #10674] by stereobooster fix https://github.com/ruby/ruby/pull/1654 Modified files: trunk/lib/net/http.rb trunk/test/net/http/test_http.rb Index: test/net/http/test_http.rb =================================================================== --- test/net/http/test_http.rb (revision 60034) +++ test/net/http/test_http.rb (revision 60035) @@ -1045,6 +1045,56 @@ class TestNetHTTPKeepAlive < Test::Unit: https://github.com/ruby/ruby/blob/trunk/test/net/http/test_http.rb#L1045 } end + class MockSocket + attr_reader :count + def initialize(success_after: nil) + @success_after = success_after + @count = 0 + end + def close + end + def closed? + end + def write(_) + end + def readline + @count += 1 + if @success_after && @success_after <= @count + "HTTP/1.1 200 OK" + else + raise Errno::ECONNRESET + end + end + def readuntil(*_) + "" + end + def read_all(_) + end + end + + def test_http_retry_success + start {|http| + socket = MockSocket.new(success_after: 10) + http.instance_variable_set(:@socket, socket) + assert_equal 0, socket.count + http.max_retries = 10 + res = http.get('/') + assert_equal 10, socket.count + assert_kind_of Net::HTTPResponse, res + assert_kind_of String, res.body + } + end + + def test_http_retry_failed + start {|http| + socket = MockSocket.new + http.instance_variable_set(:@socket, socket) + http.max_retries = 10 + assert_raise(Errno::ECONNRESET){ http.get('/') } + assert_equal 11, socket.count + } + end + def test_keep_alive_server_close def @server.run(sock) sock.close Index: lib/net/http.rb =================================================================== --- lib/net/http.rb (revision 60034) +++ lib/net/http.rb (revision 60035) @@ -670,6 +670,7 @@ module Net #:nodoc: https://github.com/ruby/ruby/blob/trunk/lib/net/http.rb#L670 @open_timeout = 60 @read_timeout = 60 @continue_timeout = nil + @max_retries = 1 @debug_output = nil @proxy_from_env = false @@ -736,6 +737,21 @@ module Net #:nodoc: https://github.com/ruby/ruby/blob/trunk/lib/net/http.rb#L737 # it raises a Net::ReadTimeout exception. The default value is 60 seconds. attr_reader :read_timeout + # Maximum number of times to retry an idempotent request in case of + # Net::ReadTimeout, IOError, EOFError, Errno::ECONNRESET, + # Errno::ECONNABORTED, Errno::EPIPE, OpenSSL::SSL, Timeout::Error + # Should be non-negative integer number. Zero means no retries. + # The default value is 1. + def max_retries=(retries) + retries = retries.to_int + if retries < 0 + raise ArgumentError, 'max_retries should be non-negative integer number' + end + @max_retries = retries + end + + attr_reader :max_retries + # Setter for the read_timeout attribute. def read_timeout=(sec) @socket.read_timeout = sec if @socket @@ -1477,7 +1493,7 @@ module Net #:nodoc: https://github.com/ruby/ruby/blob/trunk/lib/net/http.rb#L1493 # avoid a dependency on OpenSSL defined?(OpenSSL::SSL) ? OpenSSL::SSL::SSLError : IOError, Timeout::Error => exception - if count == 0 && IDEMPOTENT_METHODS_.include?(req.method) + if count < max_retries && IDEMPOTENT_METHODS_.include?(req.method) count += 1 @socket.close if @socket D "Conn close because of error #{exception}, and retry" -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/