1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
|
# frozen_string_literal: true
module HTTPX
module Plugins
# This plugin implements a session that persists connections over the duration of the process.
#
# This will improve connection reuse in a long-running process.
#
# One important caveat to note is, although this session might not close connections,
# other sessions from the same process that don't have this plugin turned on might.
#
# This session will still be able to work with it, as if, when expecting a connection
# terminated by a different session, it will just retry on a new one and keep it open.
#
# This plugin is also not recommendable when connecting to >9000 (like, a lot) different origins.
# So when you use this, make sure that you don't fall into this trap.
#
# https://gitlab.com/os85/httpx/wikis/Persistent
#
module Persistent
class << self
def load_dependencies(klass)
klass.plugin(:fiber_concurrency)
max_retries = if klass.default_options.respond_to?(:max_retries)
[klass.default_options.max_retries, 1].max
else
1
end
klass.plugin(:retries, max_retries: max_retries)
end
end
def self.extra_options(options)
options.merge(persistent: true)
end
module InstanceMethods
def close(*)
super
# traverse other threads and unlink respective selector
# WARNING: this is not thread safe, make sure that the session isn't being
# used anymore, or all non-main threads are stopped.
Thread.list.each do |th|
store = thread_selector_store(th)
next unless store && store.key?(self)
selector = store.delete(self)
selector_close(selector)
end
end
private
def retryable_request?(request, response, *)
super || begin
return false unless response && response.is_a?(ErrorResponse)
error = response.error
Retries::RECONNECTABLE_ERRORS.any? { |klass| error.is_a?(klass) }
end
end
def retryable_error?(ex, options)
super &&
# under the persistent plugin rules, requests are only retried for connection related errors,
# which do not include request timeout related errors. This only gets overriden if the end user
# manually changed +:max_retries+ to something else, which means it is aware of the
# consequences.
(!ex.is_a?(RequestTimeoutError) || options.max_retries != 1)
end
end
end
register_plugin :persistent, Persistent
end
end
|