Class: PatientHttp::ClientPool
- Inherits:
-
Object
- Object
- PatientHttp::ClientPool
- Defined in:
- lib/patient_http/client_pool.rb
Overview
Pool of HTTP clients with LRU eviction.
Maintains a pool of clients lazily instantiated for each host. The pool is capped with an LRU algorithm - when a new client is needed and the pool is at capacity, the least recently used client is closed and removed.
Constant Summary collapse
- PROTOCOLS =
Supported protocol names mapped to their async-http implementations. Forcing :http1 also limits the TLS ALPN advertisement to http/1.1, which avoids HTTP/2 negotiation with servers and middleboxes that mishandle it.
{ http1: Async::HTTP::Protocol::HTTP11, http2: Async::HTTP::Protocol::HTTP2 }.freeze
Instance Attribute Summary collapse
-
#connection_timeout ⇒ Object
readonly
Returns the value of attribute connection_timeout.
-
#max_size ⇒ Object
readonly
Returns the value of attribute max_size.
-
#protocol ⇒ Object
readonly
Returns the value of attribute protocol.
-
#proxy_url ⇒ Object
readonly
Returns the value of attribute proxy_url.
-
#retries ⇒ Object
readonly
Returns the value of attribute retries.
Instance Method Summary collapse
-
#client_for(endpoint) ⇒ Protocol::HTTP::AcceptEncoding
Get or create a client for the given endpoint.
-
#close ⇒ void
Close all clients and release resources.
-
#evict(url) ⇒ void
Evict and close the client for the given URL.
-
#initialize(max_size:, connection_timeout: nil, proxy_url: nil, retries: 3, protocol: nil) ⇒ ClientPool
constructor
A new instance of ClientPool.
-
#request(http_method, url, headers, body, &block) ⇒ Protocol::HTTP::Response
Make a request.
-
#size ⇒ Integer
Number of clients in the pool.
Constructor Details
#initialize(max_size:, connection_timeout: nil, proxy_url: nil, retries: 3, protocol: nil) ⇒ ClientPool
Returns a new instance of ClientPool.
18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/patient_http/client_pool.rb', line 18 def initialize(max_size:, connection_timeout: nil, proxy_url: nil, retries: 3, protocol: nil) if protocol && !PROTOCOLS.include?(protocol) raise ArgumentError.new("protocol must be one of #{PROTOCOLS.keys.inspect}, got: #{protocol.inspect}") end @clients = {} @max_size = max_size @connection_timeout = connection_timeout @proxy_url = proxy_url @retries = retries @protocol = protocol @mutex = Mutex.new @proxy_client = nil end |
Instance Attribute Details
#connection_timeout ⇒ Object (readonly)
Returns the value of attribute connection_timeout.
33 34 35 |
# File 'lib/patient_http/client_pool.rb', line 33 def connection_timeout @connection_timeout end |
#max_size ⇒ Object (readonly)
Returns the value of attribute max_size.
33 34 35 |
# File 'lib/patient_http/client_pool.rb', line 33 def max_size @max_size end |
#protocol ⇒ Object (readonly)
Returns the value of attribute protocol.
33 34 35 |
# File 'lib/patient_http/client_pool.rb', line 33 def protocol @protocol end |
#proxy_url ⇒ Object (readonly)
Returns the value of attribute proxy_url.
33 34 35 |
# File 'lib/patient_http/client_pool.rb', line 33 def proxy_url @proxy_url end |
#retries ⇒ Object (readonly)
Returns the value of attribute retries.
33 34 35 |
# File 'lib/patient_http/client_pool.rb', line 33 def retries @retries end |
Instance Method Details
#client_for(endpoint) ⇒ Protocol::HTTP::AcceptEncoding
Get or create a client for the given endpoint.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/patient_http/client_pool.rb', line 39 def client_for(endpoint) key = host_key(endpoint) @mutex.synchronize do if @clients.key?(key) # Move to end (most recently used) by re-inserting client = @clients.delete(key) @clients[key] = client return client end evict_lru if @clients.size >= @max_size @clients[key] = make_client(endpoint) end end |
#close ⇒ void
This method returns an undefined value.
Close all clients and release resources.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 |
# File 'lib/patient_http/client_pool.rb', line 91 def close @mutex.synchronize do @clients.each_value do |client| client.close rescue nil end @clients.clear begin @proxy_client&.close rescue nil end @proxy_client = nil end end |
#evict(url) ⇒ void
This method returns an undefined value.
Evict and close the client for the given URL.
This forces a new connection to be established on the next request to this host.
115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/patient_http/client_pool.rb', line 115 def evict(url) endpoint = Async::HTTP::Endpoint.parse(url) key = host_key(endpoint) @mutex.synchronize do client = @clients.delete(key) begin client&.close rescue nil end end end |
#request(http_method, url, headers, body, &block) ⇒ Protocol::HTTP::Response
Make a request.
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/patient_http/client_pool.rb', line 63 def request(http_method, url, headers, body, &block) endpoint = Async::HTTP::Endpoint.parse(url) client = client_for(endpoint) verb = http_method.to_s.upcase = { headers: headers, body: body, scheme: endpoint.scheme, authority: endpoint. } request = ::Protocol::HTTP::Request[verb, endpoint.path, **] response = client.call(request) return response unless block_given? begin yield response ensure response.close end end |
#size ⇒ Integer
Returns number of clients in the pool.
130 131 132 |
# File 'lib/patient_http/client_pool.rb', line 130 def size @mutex.synchronize { @clients.size } end |