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)

Returns:
  • (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)

https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
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)

Parameters:
  • 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 Hash: (**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