Class: PatientHttp::ClientPool

Inherits:
Object
  • Object
show all
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.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(max_size:, connection_timeout: nil, proxy_url: nil, retries: 3) ⇒ ClientPool

Returns a new instance of ClientPool.



10
11
12
13
14
15
16
17
18
# File 'lib/patient_http/client_pool.rb', line 10

def initialize(max_size:, connection_timeout: nil, proxy_url: nil, retries: 3)
  @clients = {}
  @max_size = max_size
  @connection_timeout = connection_timeout
  @proxy_url = proxy_url
  @retries = retries
  @mutex = Mutex.new
  @proxy_client = nil
end

Instance Attribute Details

#connection_timeoutObject (readonly)

Returns the value of attribute connection_timeout.



20
21
22
# File 'lib/patient_http/client_pool.rb', line 20

def connection_timeout
  @connection_timeout
end

#max_sizeObject (readonly)

Returns the value of attribute max_size.



20
21
22
# File 'lib/patient_http/client_pool.rb', line 20

def max_size
  @max_size
end

#proxy_urlObject (readonly)

Returns the value of attribute proxy_url.



20
21
22
# File 'lib/patient_http/client_pool.rb', line 20

def proxy_url
  @proxy_url
end

#retriesObject (readonly)

Returns the value of attribute retries.



20
21
22
# File 'lib/patient_http/client_pool.rb', line 20

def retries
  @retries
end

Instance Method Details

#client_for(endpoint) ⇒ Protocol::HTTP::AcceptEncoding

Get or create a client for the given endpoint.

Parameters:

  • endpoint (Async::HTTP::Endpoint)

    the target endpoint

Returns:

  • (Protocol::HTTP::AcceptEncoding)

    wrapped client



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/patient_http/client_pool.rb', line 26

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

#closevoid

This method returns an undefined value.

Close all clients and release resources.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/patient_http/client_pool.rb', line 78

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.

Parameters:

  • url (String)

    the request URL whose host client should be evicted



102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/patient_http/client_pool.rb', line 102

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.

Parameters:

  • http_method (String, Symbol)

    HTTP method

  • url (String)

    request URL

  • headers (Hash)

    request headers

  • body (String, nil)

    request body

  • block (Proc)

    optional block to process the response

Returns:

  • (Protocol::HTTP::Response)

    the response



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/patient_http/client_pool.rb', line 50

def request(http_method, url, headers, body, &block)
  endpoint = Async::HTTP::Endpoint.parse(url)
  client = client_for(endpoint)

  verb = http_method.to_s.upcase

  options = {
    headers: headers,
    body: body,
    scheme: endpoint.scheme,
    authority: endpoint.authority
  }

  request = ::Protocol::HTTP::Request[verb, endpoint.path, **options]
  response = client.call(request)

  return response unless block_given?

  begin
    yield response
  ensure
    response.close
  end
end

#sizeInteger

Returns number of clients in the pool.

Returns:

  • (Integer)

    number of clients in the pool



117
118
119
# File 'lib/patient_http/client_pool.rb', line 117

def size
  @mutex.synchronize { @clients.size }
end