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
22 def initialize(options)
23   @max_connections = options.fetch(:max_connections, Float::INFINITY)
24   @max_connections_per_origin = options.fetch(:max_connections_per_origin, Float::INFINITY)
25   @pool_timeout = options.fetch(:pool_timeout, POOL_TIMEOUT)
26   @resolvers = Hash.new { |hs, resolver_type| hs[resolver_type] = [] }
27   @resolver_mtx = Thread::Mutex.new
28   @connections = []
29   @connection_mtx = Thread::Mutex.new
30   @connections_counter = 0
31   @max_connections_cond = ConditionVariable.new
32   @origin_counters = Hash.new(0)
33   @origin_conds = Hash.new { |hs, orig| hs[orig] = ConditionVariable.new }
34 end

Public Instance methods

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

:nocov:

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

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

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