Class: PatientHttp::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/patient_http/configuration.rb

Overview

Configuration for the PatientHttp processor.

This class holds all configuration options for the HTTP connection pool, including connection limits, timeouts, and other HTTP client settings. It has no dependencies on any job system.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(max_connections: 256, request_timeout: 60, shutdown_timeout: 30, logger: nil, max_response_size: 1024 * 1024, user_agent: "PatientHttp", raise_error_responses: false, max_redirects: 5, connection_pool_size: 100, connection_timeout: nil, proxy_url: nil, retries: 3, encryption_key: nil) ⇒ Configuration

Initializes a new Configuration with the specified options.

Parameters:

  • max_connections (Integer) (defaults to: 256)

    Maximum number of concurrent connections

  • request_timeout (Numeric) (defaults to: 60)

    Default request timeout in seconds

  • shutdown_timeout (Numeric) (defaults to: 30)

    Graceful shutdown timeout in seconds

  • logger (Logger, nil) (defaults to: nil)

    Logger instance to use (defaults to stdout)

  • max_response_size (Integer) (defaults to: 1024 * 1024)

    Maximum response size in bytes

  • user_agent (String, nil) (defaults to: "PatientHttp")

    Default User-Agent header value

  • raise_error_responses (Boolean) (defaults to: false)

    Whether to raise HttpError for non-2xx responses by default

  • max_redirects (Integer) (defaults to: 5)

    Maximum number of redirects to follow (0 disables redirects)

  • connection_pool_size (Integer) (defaults to: 100)

    Maximum number of host clients to pool

  • connection_timeout (Numeric, nil) (defaults to: nil)

    Connection timeout in seconds

  • proxy_url (String, nil) (defaults to: nil)

    HTTP/HTTPS proxy URL (supports authentication)

  • retries (Integer) (defaults to: 3)

    Number of retries for failed requests



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/patient_http/configuration.rb', line 66

def initialize(
  max_connections: 256,
  request_timeout: 60,
  shutdown_timeout: 30,
  logger: nil,
  max_response_size: 1024 * 1024,
  user_agent: "PatientHttp",
  raise_error_responses: false,
  max_redirects: 5,
  connection_pool_size: 100,
  connection_timeout: nil,
  proxy_url: nil,
  retries: 3,
  encryption_key: nil
)
  @mutex = Mutex.new

  # Initialize payload store configuration
  @payload_stores = {}
  @default_payload_store_name = nil

  # Initialize secret configuration
  @secrets = {}
  @secret_manager = SecretManager.new

  @encryptor = nil

  self.max_connections = max_connections
  self.request_timeout = request_timeout
  self.shutdown_timeout = shutdown_timeout
  self.logger = logger || Logger.new($stderr, level: Logger::ERROR)
  self.max_response_size = max_response_size
  self.user_agent = user_agent
  self.raise_error_responses = raise_error_responses
  self.max_redirects = max_redirects
  self.connection_pool_size = connection_pool_size
  self.connection_timeout = connection_timeout
  self.proxy_url = proxy_url
  self.retries = retries
  self.encryption_key = encryption_key
end

Instance Attribute Details

#connection_pool_sizeInteger

Returns This is the maximum number of hosts for which connections will be kept alive for at one time.

Returns:

  • (Integer)

    This is the maximum number of hosts for which connections will be kept alive for at one time.



38
39
40
# File 'lib/patient_http/configuration.rb', line 38

def connection_pool_size
  @connection_pool_size
end

#connection_timeoutNumeric?

Returns Connection timeout in seconds.

Returns:

  • (Numeric, nil)

    Connection timeout in seconds



41
42
43
# File 'lib/patient_http/configuration.rb', line 41

def connection_timeout
  @connection_timeout
end

#default_payload_store_nameSymbol? (readonly)

Get the name of the default payload store.

Returns:

  • (Symbol, nil)

    The default store name or nil if none registered



304
305
306
# File 'lib/patient_http/configuration.rb', line 304

def default_payload_store_name
  @default_payload_store_name
end

#loggerLogger

Get the logger to use to report pool events. Default is to log errors to STDERR.

Returns:

  • (Logger)

    the logger instance



110
111
112
# File 'lib/patient_http/configuration.rb', line 110

def logger
  @logger
end

#max_connectionsInteger

Returns Maximum number of concurrent connections.

Returns:

  • (Integer)

    Maximum number of concurrent connections



16
17
18
# File 'lib/patient_http/configuration.rb', line 16

def max_connections
  @max_connections
end

#max_redirectsInteger

Returns Maximum number of redirects to follow (0 disables redirects).

Returns:

  • (Integer)

    Maximum number of redirects to follow (0 disables redirects)



34
35
36
# File 'lib/patient_http/configuration.rb', line 34

def max_redirects
  @max_redirects
end

#max_response_sizeInteger

Returns Maximum response size in bytes.

Returns:

  • (Integer)

    Maximum response size in bytes



25
26
27
# File 'lib/patient_http/configuration.rb', line 25

def max_response_size
  @max_response_size
end

#proxy_urlString?

Returns HTTP/HTTPS proxy URL (supports authentication).

Returns:

  • (String, nil)

    HTTP/HTTPS proxy URL (supports authentication)



44
45
46
# File 'lib/patient_http/configuration.rb', line 44

def proxy_url
  @proxy_url
end

#raise_error_responsesBoolean

Returns Whether to raise HttpError for non-2xx responses by default.

Returns:

  • (Boolean)

    Whether to raise HttpError for non-2xx responses by default



31
32
33
# File 'lib/patient_http/configuration.rb', line 31

def raise_error_responses
  @raise_error_responses
end

#request_timeoutNumeric

Returns Default request timeout in seconds.

Returns:

  • (Numeric)

    Default request timeout in seconds



19
20
21
# File 'lib/patient_http/configuration.rb', line 19

def request_timeout
  @request_timeout
end

#retriesInteger

Returns Number of retries for failed requests.

Returns:

  • (Integer)

    Number of retries for failed requests



47
48
49
# File 'lib/patient_http/configuration.rb', line 47

def retries
  @retries
end

#secret_managerSecretManager (readonly)

Returns the secret manager instance.

Returns:



50
51
52
# File 'lib/patient_http/configuration.rb', line 50

def secret_manager
  @secret_manager
end

#shutdown_timeoutNumeric

Returns Graceful shutdown timeout in seconds.

Returns:

  • (Numeric)

    Graceful shutdown timeout in seconds



22
23
24
# File 'lib/patient_http/configuration.rb', line 22

def shutdown_timeout
  @shutdown_timeout
end

#user_agentString?

Returns Default User-Agent header value.

Returns:

  • (String, nil)

    Default User-Agent header value



28
29
30
# File 'lib/patient_http/configuration.rb', line 28

def user_agent
  @user_agent
end

Instance Method Details

#decryption(callable = nil) {|data| ... } ⇒ Object

Set the decryption callable for decrypting payloads after deserialization.

Parameters:

  • callable (#call, nil) (defaults to: nil)

    An object that responds to #call, taking data and returning decrypted data

Yields:

  • (data)

    A block that takes data and returns decrypted data

Raises:

  • (ArgumentError)

    If both callable and block are provided, or if callable doesn’t respond to #call



182
183
184
185
# File 'lib/patient_http/configuration.rb', line 182

def decryption(callable = nil, &block)
  @decryption = resolve_callable(:decryption, callable, &block)
  @encryptor = nil
end

#encryption(callable = nil) {|data| ... } ⇒ Object

Set the encryption callable for encrypting payloads before serialization.

Parameters:

  • callable (#call, nil) (defaults to: nil)

    An object that responds to #call, taking data and returning encrypted data

Yields:

  • (data)

    A block that takes data and returns encrypted data

Raises:

  • (ArgumentError)

    If both callable and block are provided, or if callable doesn’t respond to #call



172
173
174
175
# File 'lib/patient_http/configuration.rb', line 172

def encryption(callable = nil, &block)
  @encryption = resolve_callable(:encryption, callable, &block)
  @encryptor = nil
end

#encryption_key=(keys) ⇒ Object



187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/patient_http/configuration.rb', line 187

def encryption_key=(keys)
  keys = Array(keys).map(&:to_s).reject(&:empty?)
  if keys.empty?
    @encryption = nil
    @decryption = nil
    @encryptor = nil
    return
  end

  unless defined?(ActiveSupport::MessageEncryptor)
    begin
      require "active_support/key_generator"
      require "active_support/message_encryptor"
    rescue LoadError
      raise ArgumentError.new("ActiveSupport::MessageEncryptor is required for encryption_key")
    end
  end

  key_length = ActiveSupport::MessageEncryptor.key_len
  key_generator = lambda do |key|
    ActiveSupport::KeyGenerator.new(key).generate_key(SALT, key_length)
  end

  encryptor = ActiveSupport::MessageEncryptor.new(key_generator.call(keys.first), cipher: "aes-256-gcm")
  keys[1..].each { |key| encryptor.rotate(key_generator.call(key)) }

  encryption { |data| encryptor.encrypt_and_sign(data) }
  decryption { |data| encryptor.decrypt_and_verify(data) }
  @encryptor = nil
end

#encryptorEncryptor

Return an Encryptor instance. If encryption and decryption are not set, then this will be an empty Encryptor that returns data unchanged.

Returns:



222
223
224
# File 'lib/patient_http/configuration.rb', line 222

def encryptor
  @encryptor ||= Encryptor.new(encryption: @encryption, decryption: @decryption)
end

#payload_store(name = nil) ⇒ PayloadStore::Base?

Get a registered payload store by name.

Parameters:

  • name (Symbol, String, nil) (defaults to: nil)

    Store name. If nil, returns the default store.

Returns:



291
292
293
294
295
296
297
298
299
# File 'lib/patient_http/configuration.rb', line 291

def payload_store(name = nil)
  if name.nil?
    return nil unless @default_payload_store_name

    @payload_stores[@default_payload_store_name]
  else
    @payload_stores[name.to_sym]
  end
end

#payload_storesHash{Symbol => PayloadStore::Base}

Get all registered payload stores.

Returns:



309
310
311
# File 'lib/patient_http/configuration.rb', line 309

def payload_stores
  @payload_stores.dup
end

#register_payload_store(name, adapter:, **options) ⇒ void

This method returns an undefined value.

Register a payload store for external storage of large payloads.

The name is included in the serialized references to the stored data. Changing it will cause any existing reference to become invalid.

Multiple stores can be registered for migration purposes. The last store registered becomes the default used for new writes. References to other registered stores remain valid for reading.

Parameters:

  • name (Symbol, String)

    Unique name for this store registration

  • adapter (Symbol, String)

    The adapter type (:file, :redis, :s3, etc.)

  • options (Hash)

    Options passed to the adapter constructor

Raises:

  • (ArgumentError)

    If the adapter is not registered



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
# File 'lib/patient_http/configuration.rb', line 267

def register_payload_store(name, adapter:, **options)
  name = name.to_sym
  adapter = adapter.to_sym

  # Trigger autoload for common adapters
  ensure_adapter_loaded(adapter)

  unless PayloadStore::Base.lookup(adapter)
    raise ArgumentError, "Unknown payload store adapter: #{adapter.inspect}. " \
      "Available adapters: #{PayloadStore::Base.registered_adapters.inspect}"
  end

  store = PayloadStore::Base.create(adapter, **options)

  @mutex.synchronize do
    @payload_stores = @payload_stores.merge(name => store)
    @default_payload_store_name = name
  end
end

#register_secret(name, value = nil) {|name| ... } ⇒ void

This method returns an undefined value.

Register a named secret whose value can be referenced indirectly when building requests via PatientHttp.secret.

The value can be provided directly or as a block (callable). A block is invoked lazily with the secret name each time the secret is resolved, which is useful for values that should be read on demand (for example, from the environment).

Parameters:

  • name (String, Symbol)

    the secret name

  • value (Object, nil) (defaults to: nil)

    the secret value (omit when providing a block)

Yields:

  • (name)

    a block that returns the secret value (omit when providing a value)

Raises:

  • (ArgumentError)

    if neither or both of value and block are provided



238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/patient_http/configuration.rb', line 238

def register_secret(name, value = nil, &block)
  if value.nil? && block.nil?
    raise ArgumentError.new("register_secret requires a value or a block")
  end

  if !value.nil? && block
    raise ArgumentError.new("register_secret accepts either a value or a block, not both")
  end

  @mutex.synchronize do
    @secrets[name.to_s] = block || value
    @secret_manager = SecretManager.new(secrets: @secrets.dup)
  end
end

#to_hHash

Convert to hash for inspection

Returns:

  • (Hash)

    hash representation with string keys



315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
# File 'lib/patient_http/configuration.rb', line 315

def to_h
  {
    "max_connections" => max_connections,
    "request_timeout" => request_timeout,
    "shutdown_timeout" => shutdown_timeout,
    "logger" => logger,
    "max_response_size" => max_response_size,
    "user_agent" => user_agent,
    "raise_error_responses" => raise_error_responses,
    "max_redirects" => max_redirects,
    "connection_pool_size" => connection_pool_size,
    "connection_timeout" => connection_timeout,
    "proxy_url" => proxy_url,
    "retries" => retries,
    "payload_stores" => payload_stores.keys,
    "default_payload_store" => default_payload_store_name,
    "secrets" => @mutex.synchronize { @secrets.keys }
  }
end