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
125 def checkin_resolver(resolver)
126   @resolver_mtx.synchronize do
127     resolvers = @resolvers[resolver.class]
128 
129     resolver = resolver.multi
130 
131     resolvers << resolver unless resolvers.include?(resolver)
132   end
133 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     @connections.delete_at(idx) if idx
104   end
105 end
checkout_resolver(options)
[show source]
    # File lib/httpx/pool.rb
111 def checkout_resolver(options)
112   resolver_type = options.resolver_class
113   resolver_type = Resolver.resolver_for(resolver_type)
114 
115   @resolver_mtx.synchronize do
116     resolvers = @resolvers[resolver_type]
117 
118     idx = resolvers.find_index do |res|
119       res.options == options
120     end
121     resolvers.delete_at(idx) if idx
122   end || checkout_new_resolver(resolver_type, options)
123 end
inspect()

:nocov:

[show source]
    # File lib/httpx/pool.rb
136 def inspect
137   "#<#{self.class}:#{object_id} " \
138     "@max_connections_per_origin=#{@max_connections_per_origin} " \
139     "@pool_timeout=#{@pool_timeout} " \
140     "@connections=#{@connections.size}>"
141 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
107 def reset_resolvers
108   @resolver_mtx.synchronize { @resolvers.clear }
109 end