class HTTPX::Pool

  1. lib/httpx/pool.rb
Superclass: Object

Constants

POOL_TIMEOUT = 5  

Public Class methods

new(options)

Sets up the connection pool with the given options, which can be the following:

:max_connections

the maximum number of connections held in the pool.

:max_connections_per_origin

the maximum number of connections held in the pool pointing to a given origin.

:pool_timeout

the number of seconds to wait for a connection to a given origin (before raising HTTPX::PoolTimeoutError)

[show source]
   # File lib/httpx/pool.rb
20 def initialize(options)
21   @max_connections = options.fetch(:max_connections, Float::INFINITY)
22   @max_connections_per_origin = options.fetch(:max_connections_per_origin, Float::INFINITY)
23   @pool_timeout = options.fetch(:pool_timeout, POOL_TIMEOUT)
24   @resolvers = Hash.new { |hs, resolver_type| hs[resolver_type] = [] }
25   @resolver_mtx = Thread::Mutex.new
26   @connections = []
27   @connection_mtx = Thread::Mutex.new
28   @connections_counter = 0
29   @max_connections_cond = ConditionVariable.new
30   @origin_counters = Hash.new(0)
31   @origin_conds = Hash.new { |hs, orig| hs[orig] = ConditionVariable.new }
32 end

Public Instance methods

checkin_connection(connection)
[show source]
   # File lib/httpx/pool.rb
85 def checkin_connection(connection)
86   return if connection.options.io
87 
88   @connection_mtx.synchronize do
89     @connections << connection
90 
91     @max_connections_cond.signal
92     @origin_conds[connection.origin.to_s].signal
93   end
94 end
checkin_resolver(resolver)
[show source]
    # File lib/httpx/pool.rb
128 def checkin_resolver(resolver)
129   @resolver_mtx.synchronize do
130     resolvers = @resolvers[resolver.class]
131 
132     resolver = resolver.multi
133 
134     resolvers << resolver unless resolvers.include?(resolver)
135   end
136 end
checkout_connection(uri, options)

opens a connection to the IP reachable through uri. Many hostnames are reachable through the same IP, so we try to maximize pipelining by opening as few connections as possible.

[show source]
   # File lib/httpx/pool.rb
45 def checkout_connection(uri, options)
46   return checkout_new_connection(uri, options) if options.io
47 
48   @connection_mtx.synchronize do
49     acquire_connection(uri, options) || begin
50       if @connections_counter == @max_connections
51         # this takes precedence over per-origin
52         @max_connections_cond.wait(@connection_mtx, @pool_timeout)
53 
54         acquire_connection(uri, options) || begin
55           if @connections_counter == @max_connections
56             # if no matching usable connection was found, the pool will make room and drop a closed connection. if none is found,
57             # this means that all of them are persistent or being used, so raise a timeout error.
58             conn = @connections.find { |c| c.state == :closed }
59 
60             raise PoolTimeoutError.new(@pool_timeout,
61                                        "Timed out after #{@pool_timeout} seconds while waiting for a connection") unless conn
62 
63             drop_connection(conn)
64           end
65         end
66       end
67 
68       if @origin_counters[uri.origin] == @max_connections_per_origin
69 
70         @origin_conds[uri.origin].wait(@connection_mtx, @pool_timeout)
71 
72         return acquire_connection(uri, options) ||
73                raise(PoolTimeoutError.new(@pool_timeout,
74                                           "Timed out after #{@pool_timeout} seconds while waiting for a connection to #{uri.origin}"))
75       end
76 
77       @connections_counter += 1
78       @origin_counters[uri.origin] += 1
79 
80       checkout_new_connection(uri, options)
81     end
82   end
83 end
checkout_mergeable_connection(connection)
[show source]
    # File lib/httpx/pool.rb
 96 def checkout_mergeable_connection(connection)
 97   return if connection.options.io
 98 
 99   @connection_mtx.synchronize do
100     idx = @connections.find_index do |ch|
101       ch != connection && ch.mergeable?(connection)
102     end
103     if idx
104       @connections_counter -= 1
105       @connections.delete_at(idx)
106     end
107   end
108 end
checkout_resolver(options)
[show source]
    # File lib/httpx/pool.rb
114 def checkout_resolver(options)
115   resolver_type = options.resolver_class
116   resolver_type = Resolver.resolver_for(resolver_type)
117 
118   @resolver_mtx.synchronize do
119     resolvers = @resolvers[resolver_type]
120 
121     idx = resolvers.find_index do |res|
122       res.options == options
123     end
124     resolvers.delete_at(idx) if idx
125   end || checkout_new_resolver(resolver_type, options)
126 end
inspect()

:nocov:

[show source]
    # File lib/httpx/pool.rb
139 def inspect
140   "#<#{self.class}:#{object_id} " \
141     "@max_connections_per_origin=#{@max_connections_per_origin} " \
142     "@pool_timeout=#{@pool_timeout} " \
143     "@connections=#{@connections.size}>"
144 end
pop_connection()

connections returned by this function are not expected to return to the connection pool.

[show source]
   # File lib/httpx/pool.rb
35 def pop_connection
36   @connection_mtx.synchronize do
37     drop_connection
38   end
39 end
reset_resolvers()
[show source]
    # File lib/httpx/pool.rb
110 def reset_resolvers
111   @resolver_mtx.synchronize { @resolvers.clear }
112 end