class Async::HTTP::Pool
#reusable? -> can be used again.
#multiplex -> 1 or more.
Resources must respond to
This pool doesn’t impose a maximum number of open resources, but it WILL block if there are no available resources and trying to allocate another one fails.
In general we don’t know the policy until connection is established.
- Multiplex requests per connection (HTTP2)
- Multiple sequential requests per connection (HTTP1 with keep-alive)
- Single request per connection (HTTP/1 without keep-alive)
Pool behaviours
def acquire
def acquire resource = wait_for_next_available return resource unless block_given? begin yield resource ensure release(resource) end end
def close
def close @available.each_key(&:close) @available.clear end
def create_resource
def create_resource begin # This might fail, which is okay :) resource = @constructor.call rescue StandardError Async.logger.error "#{$!}: #{$!.backtrace}" return nil end @available[resource] = 1 return resource end
def initialize(limit = nil, &block)
def initialize(limit = nil, &block) @available = {} # resource => count @waiting = [] @limit = limit @constructor = block end
def next_available
def next_available @available.each do |resource, count| if count < resource.multiplex @available[resource] += 1 return resource end end if !@limit or @available.count < @limit Async.logger.debug(self) {"No available resources, allocating new one..."} return create_resource end end
def release(resource)
def release(resource) if resource.reusable? Async.logger.debug(self) {"Reusing resource #{resource}"} @available[resource] -= 1 if task = @waiting.pop task.resume end else Async.logger.debug(self) {"Closing resource: #{resource}"} resource.close end end
def wait_for_next_available
def wait_for_next_available until resource = next_available @waiting << Fiber.current Task.yield end return resource end