Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Net::HTTP – Flush or Close

I've written a consumer for a payment API. My code simply issues a POST request and gets a response from the API. I've implemented that with Net::HTTP, here are the relevant lines of code:

http = Net::HTTP.new(uri.host, 443)
http.use_ssl = true
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = Net::HTTP::Post.new(uri.request_uri)
request.set_form_data(params)
response = http.request(request)

This worked for years, however, recently some requests have reached timeouts when the API is under stress. The API maintainer came up with this explanation:

We pass on the data to RabbitMQ synchronously after flushing the HTTP response. Apparently, some HTTP libs wait for the connection to be closed before the program continues on the consumer side and we think this is happening here. Please reconfigure your consumer not to wait for close but to continue right after the response has been flushed.

I'm not sure how Net::HTTP is implemented and whether it really waits for the close when the response has been flushed. The docs don't say anything about it nor is there a setting to control any of this. And to make matters worse, I don't really know how to simulate this.

Any ideas are very welcome!

like image 323
svoop Avatar asked Sep 20 '26 08:09

svoop


1 Answers

I guess the following experiment (with Ruby 2.3) should give the answer, I post it here in case someone else stumbles across this question in the future.

server.rb:

require 'socket'

server = TCPServer.new('localhost', 2345)
loop do
  socket = server.accept
  request = socket.gets
  STDERR.puts request
  response = "Hello World at #{Time.now}!\n"
  socket.print "HTTP/1.1 200 OK\r\n" +
               "Content-Type: text/plain\r\n" +
               "Content-Length: #{response.bytesize}\r\n" +
               "Connection: close\r\n"
  socket.print "\r\n"
  socket.print response
  socket.flush
  sleep 10
  socket.close
end

client.rb:

require 'net/http'

http = Net::HTTP.new('localhost', 2345)
request = Net::HTTP::Post.new('/')
response = http.request(request)
puts response.body

Running the server, the client will send one request and exit. It does so immediately, so the flush is sufficient to have the client code continue. Restarting the client within the 10 seconds wait of the server, causes the client the hang until the 10 seconds have fully elapsed, then printing the Hello World and once again immediately exiting.

In other words: Such a simple Net::HTTP client does not wait for the connection to close but continues to execute it's code once the server has flushed.

like image 176
svoop Avatar answered Sep 24 '26 01:09

svoop



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!