class Faraday::Request::Retry
and 0.075 and a second interval that is random between 0.1 and 0.125.
This example will result in a first interval that is random between 0.05
end
conn.adapter(:net_http) # NB: Last middleware must be the adapter
exceptions: [CustomException, ‘Timeout::Error’])
backoff_factor: 2,
interval_randomness: 0.5,
interval: 0.05,
conn.request(:retry, max: 2,
Faraday.new do |conn|
@example Configure Retry middleware using intervals
interval, and a backoff factor.
handle, a retry interval, a percentage of randomness to add to the retry
be configured with an arbitrary number of retries, a list of exceptions to
By default, it retries 2 times and handles only timeout exceptions. It can
Catches exceptions and retries each request a limited number of times.
def build_exception_matcher(exceptions)
-
(Module)
- an exception matcher
Other tags:
- Api: - private
Parameters:
-
exceptions
(Array
) --
def build_exception_matcher(exceptions) matcher = Module.new ( class << matcher self end).class_eval do define_method(:===) do |error| exceptions.any? do |ex| if ex.is_a? Module error.is_a? ex else Object.const_defined?(ex.to_s) && error.is_a?(Object.const_get(ex.to_s)) end end end end matcher end
def calculate_retry_after(env)
MDN spec for Retry-After header:
def calculate_retry_after(env) response_headers = env[:response_headers] return unless response_headers retry_after_value = env[:response_headers]['Retry-After'] # Try to parse date from the header value begin datetime = DateTime.rfc2822(retry_after_value) datetime.to_time - Time.now.utc rescue ArgumentError retry_after_value.to_f end end
def calculate_retry_interval(retries)
def calculate_retry_interval(retries) retry_index = @options.max - retries current_interval = @options.interval * (@options.backoff_factor**retry_index) current_interval = [current_interval, @options.max_interval].min random_interval = rand * @options.interval_randomness.to_f * @options.interval current_interval + random_interval end
def calculate_sleep_amount(retries, env)
def calculate_sleep_amount(retries, env) retry_after = calculate_retry_after(env) retry_interval = calculate_retry_interval(retries) return if retry_after && retry_after > @options.max_interval if retry_after && retry_after >= retry_interval retry_after else retry_interval end end
def call(env)
-
env
(Faraday::Env
) --
def call(env) retries = @options.max request_body = env[:body] begin # after failure env[:body] is set to the response body env[:body] = request_body @app.call(env).tap do |resp| if @options.retry_statuses.include?(resp.status) raise Faraday::RetriableResponse.new(nil, resp) end end rescue @errmatch => e if retries.positive? && retry_request?(env, e) retries -= 1 rewind_files(request_body) @options.retry_block.call(env, @options, retries, e) if (sleep_amount = calculate_sleep_amount(retries + 1, env)) sleep sleep_amount retry end end raise unless e.is_a?(Faraday::RetriableResponse) e.response end end
def initialize(app, options = nil)
(**options)
-
:retry_statuses
(Array
) -- Array of Integer HTTP status -
:retry_block
(Block
) -- block that is executed before -
:retry_if
(Block
) -- block that will receive -
:methods
(Array
) -- the idempotent HTTP methods -
:exceptions
(Array
) -- [ Errno::ETIMEDOUT, -
:backoff_factor
(Integer
) -- The amount to multiply -
:max_interval
(Integer
) -- An upper limit -
:interval_randomness
(Integer
) -- The maximum random -
:interval
(Integer
) -- Pause in seconds between retries -
:max
(Integer
) -- Maximum number of retries
Parameters:
-
options
(Hash
) -- -
app
(#call
) --
def initialize(app, options = nil) super(app) @options = Options.from(options) @errmatch = build_exception_matcher(@options.exceptions) end
def retry_request?(env, exception)
def retry_request?(env, exception) @options.methods.include?(env[:method]) || @options.retry_if.call(env, exception) end
def rewind_files(body)
def rewind_files(body) return unless body.is_a?(Hash) body.each do |_, value| value.rewind if value.is_a?(UploadIO) end end