socketry / async-http

MIT License
298 stars 45 forks source link

How to keep connection alive? #29

Closed tonytonyjan closed 4 years ago

tonytonyjan commented 4 years ago

It seems like neither Async::HTTP::Internet nor Async::HTTP::Client can reuse the same http connection for sending multiple request.

It can be done by built-in net/http:

require 'net/http'
Net::HTTP.start('localhost', 9292) do |http|
  3.times do
    http.get('/')
    sleep 1
  end
end

with Async::HTTP::Internet, the following example will create conneciton per request:

Async do |task|
  internet = Async::HTTP::Internet.new
  3.times do
    response = internet.get("http://localhost:9292")
    response.close
    task.sleep 1
  end
ensure
  internet.close
end.wait

with Async::HTTP::Client, the following example will create conneciton per request:

Async do |task|
  client = Async::HTTP::Client.new(Async::HTTP::Endpoint.parse('http://localhost:9292'))
  3.times do
    response = client.get('/')
    response.close
    task.sleep 1
  end
ensure
  client.close
end.wait

I use the command below to see if requests' port are the same which means it uses the same TCP connection.

sudo tcpdump -i lo0 dst port 9292
tonytonyjan commented 4 years ago

I found the following example would reuse the same connection:

Async do |task|
  client = Async::HTTP::Client.new(Async::HTTP::Endpoint.parse('http://localhost:9292'))
  3.times do
    response = client.get('/')
    response.read
    task.sleep 1
  end
end.wait

To reuse the same connection, calling response#read is necessary.

ioquatix commented 4 years ago

Response#close will immediately terminate the response. If there is no response body, this will still be able to reuse the connection. Otherwise, maybe the server will send 1GB of data. We have no choice but to close the connection.

For HTTP/2, the stream will be reset, which still allows the underlying connection to be reused.