Net::HTTP read_timeout causes double requests
vassilevsky opened this issue · 4 comments
Hello :)
Test script:
require 'net/http'
uri = URI('http://localhost:4567/foo/bar')
Net::HTTP.start(uri.host, uri.port, read_timeout: 1) do |http|
http.request(Net::HTTP::Get.new(uri))
end
Test server output:
$ ruby -r sinatra -e 'get("/foo/bar"){ sleep 3; "baz" }'
== Sinatra/1.4.5 has taken the stage on 4567 for development with backup from Thin
Thin web server (v1.6.2 codename Doc Brown)
Maximum connections set to 1024
Listening on localhost:4567, CTRL+C to stop
127.0.0.1 - - [21/Dec/2015:00:03:21 +0300] "GET /foo/bar HTTP/1.1" 200 3 3.0183
127.0.0.1 - - [21/Dec/2015:00:03:22 +0300] "GET /foo/bar HTTP/1.1" 200 3 3.0059
I think this retry
statement is to blame:
https://github.com/ruby/ruby/blob/v2_2_4/lib/net/http.rb#L1436
I'm not sure what to do with this information. The behaviour is unexpected. Add a warning maybe?
Great, thanks @vassilevsky! Looks like the ability to configure the retry is an outstanding feature request. https://bugs.ruby-lang.org/issues/10674
Thanks for this, it just solved nearly 6 hours of shaking my fist... The api I was interacting with was slow on a DELETE request, and due to not being idempotent, the double tap was causing an error to be returned due to resource not existing.
I was able to solve via the following:
def delete_request(url, payload)
uri = URI(url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
http.read_timeout = 120 # <---- added this to help overcome the issue
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
req = Net::HTTP::Delete.new(uri.path, 'Content-Type' => 'application/json')
req.body = payload.to_json
http.request(req)
end
I have to say that since discovering this peculiarity of Ruby standard HTTP client, I used http gem for all production HTTP interaction where possible. It's good.
So, the fix would be something like this:
require 'net/http'
uri = URI('http://localhost:4567/foo/bar')
Net::HTTP.start(uri.host, uri.port, read_timeout: 1) do |http|
http.max_retries = 0 # Fix http retries
http.request(Net::HTTP::Get.new(uri))
end