socketry / async-http

MIT License
298 stars 45 forks source link

How to force close `::Async::HTTP::Internet` instance without calling `response.read` #142

Closed arseny-emchik closed 9 months ago

arseny-emchik commented 9 months ago

Hi! I make requests using ::Async::HTTP::Internet.new. Everything works well until there is an error before reading the body of the response. So closing ::Async::HTTP::Internet instance without calling response.read leads to Waiting for Async::HTTP::Protocol::HTTP1 pool to drain: #<Async::Pool::Controller(1/∞) 1/1/1> error which blocks the Fiber process (infinity loop I guess).

Question: Is there any way how to force close ::Async::HTTP::Internet instance without calling .read function?

Code example:

def make_get_request(url)
  client_instance = ::Async::HTTP::Internet.new
  response = client_instance.get(url)
  raise "Any Error" # Any logic that can raise an exception
  response.read
ensure
  client_instance.close # Warning and Fiber process hanging => Waiting for Async::HTTP::Protocol::HTTP1 pool to drain: #<Async::Pool::Controller(1/∞) 1/1/1>
end
Screenshot 2023-10-02 at 12 50 44

Research: The error happens here in the Async::Client#close function:

def close
  while @pool.busy?
    Console.logger.warn(self) { "Waiting for #{@protocol} pool to drain: #{@pool}" }
    @pool.wait
  end

  @pool.close
end

I would appreciate any help! Thank you!

ioquatix commented 9 months ago

I think the simplest solution is to ensure you have

ensure
  response&.close
  client_instance&.close
arseny-emchik commented 9 months ago

@ioquatix Thank you for explaining how to do this! That works