module ActiveMerchant::NetworkConnectionRetries

Constants

DEFAULT_CONNECTION_ERRORS
DEFAULT_RETRIES

Public Class Methods

included(base) click to toggle source
# File lib/active_merchant/network_connection_retries.rb, line 16
def self.included(base)
  base.send(:attr_accessor, :retry_safe)
end
log(logger, level, message, tag=nil) click to toggle source
# File lib/active_merchant/network_connection_retries.rb, line 39
def self.log(logger, level, message, tag=nil)
  tag ||= self.class.to_s
  message = "[#{tag}] #{message}"
  logger&.send(level, message)
end

Public Instance Methods

retry_exceptions(options={}) { || ... } click to toggle source
# File lib/active_merchant/network_connection_retries.rb, line 20
def retry_exceptions(options={})
  connection_errors = DEFAULT_CONNECTION_ERRORS.merge(options[:connection_exceptions] || {})

  retry_network_exceptions(options) do
    begin
      yield
    rescue Errno::ECONNREFUSED => e
      raise ActiveMerchant::RetriableConnectionError.new('The remote server refused the connection', e)
    rescue OpenSSL::X509::CertificateError => e
      NetworkConnectionRetries.log(options[:logger], :error, e.message, options[:tag])
      raise ActiveMerchant::ClientCertificateError, 'The remote server did not accept the provided SSL certificate'
    rescue Zlib::BufError
      raise ActiveMerchant::InvalidResponseError, 'The remote server replied with an invalid response'
    rescue *connection_errors.keys => e
      raise ActiveMerchant::ConnectionError.new(derived_error_message(connection_errors, e.class), e)
    end
  end
end

Private Instance Methods

derived_error_message(errors, klass) click to toggle source
# File lib/active_merchant/network_connection_retries.rb, line 75
def derived_error_message(errors, klass)
  key = (errors.keys & klass.ancestors).first
  key ? errors[key] : nil
end
log_with_retry_details(logger, attempts, time, message, tag) click to toggle source
# File lib/active_merchant/network_connection_retries.rb, line 71
def log_with_retry_details(logger, attempts, time, message, tag)
  NetworkConnectionRetries.log(logger, :info, 'connection_attempt=%d connection_request_time=%.4fs connection_msg="%s"' % [attempts, time, message], tag)
end
retry_network_exceptions(options = {}) { || ... } click to toggle source
# File lib/active_merchant/network_connection_retries.rb, line 47
def retry_network_exceptions(options = {})
  initial_retries = options[:max_retries] || DEFAULT_RETRIES
  retries = initial_retries
  request_start = nil

  begin
    request_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
    result = yield
    log_with_retry_details(options[:logger], initial_retries-retries + 1, Process.clock_gettime(Process::CLOCK_MONOTONIC) - request_start, 'success', options[:tag])
    result
  rescue ActiveMerchant::RetriableConnectionError => e
    retries -= 1

    log_with_retry_details(options[:logger], initial_retries-retries, Process.clock_gettime(Process::CLOCK_MONOTONIC) - request_start, e.message, options[:tag])
    retry unless retries.zero?
    raise ActiveMerchant::ConnectionError.new(e.message, e)
  rescue ActiveMerchant::ConnectionError, ActiveMerchant::InvalidResponseError => e
    retries -= 1
    log_with_retry_details(options[:logger], initial_retries-retries, Process.clock_gettime(Process::CLOCK_MONOTONIC) - request_start, e.message, options[:tag])
    retry if (options[:retry_safe] || retry_safe) && !retries.zero?
    raise
  end
end