class Faraday::Retry::Middleware
IMPORTANT: Remember to call ‘@app.call(env)` or `super` to not interrupt the middleware chain!
(see “retry” middleware: github.com/lostisland/faraday/blob/main/lib/faraday/request/retry.rb#L142).
You may need to in case you need to “wrap” the request or need more control
This already calls on_request and on_complete, so you normally don’t need to override it.
* call(env) - the main middleware invocation method.
* initialize(app, options = {}) - the initializer method
Optionally, you can also override the following methods from Faraday::Middleware
* on_complete - called when the response is being processed
* on_request - called when the request is being prepared
Your middleware can implement any of the following methods:
This class provides the main implementation for your middleware.
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_rate_limit_reset(env)
RFC for RateLimit Header Fields for HTTP:
def calculate_rate_limit_reset(env) reset_header = @options.rate_limit_reset_header || 'RateLimit-Reset' parse_retry_header(env, reset_header) end
def calculate_retry_after(env)
MDN spec for Retry-After header:
def calculate_retry_after(env) retry_header = @options.rate_limit_retry_header || 'Retry-After' parse_retry_header(env, retry_header) 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), calculate_rate_limit_reset(env)].compact.max 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] with_retries(env: env, options: @options, retries: retries, body: request_body, errmatch: @errmatch) do # after failure env[:body] is set to the response body env[:body] = request_body @app.call(env).tap do |resp| raise Faraday::RetriableResponse.new(nil, resp) if @options.retry_statuses.include?(resp.status) end end end
def initialize(app, options = nil)
(**options)
-
:exhausted_retries_block
(Block
) -- block will receive -
:header_parser_block
(Block
) -- block that will receive -
: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 parse_retry_header(env, header)
def parse_retry_header(env, header) response_headers = env[:response_headers] return unless response_headers retry_after_value = env[:response_headers][header] if @options.header_parser_block @options.header_parser_block.call(retry_after_value) else # 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 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 defined?(Faraday::UploadIO) return unless body.is_a?(Hash) body.each do |_, value| value.rewind if value.is_a?(Faraday::UploadIO) end end