123456789_123456789_123456789_123456789_123456789_

Class: ActiveRecord::ConnectionAdapters::RactorConnectionHandler::Proxy::ErrorResponse

Overview

Shareable stand-in for a main-side exception

Class Method Summary

Instance Method Summary

Constructor Details

.new(error) ⇒ ErrorResponse

[ GitHub ]

  
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy.rb', line 23

def initialize(error)
  @error_class = error.class
  @message = error.message.to_s
  @backtrace = error.backtrace
  @cause = ErrorResponse.new(error.cause) if error.cause
  @ivars = capture_ivars(error) if reconstructible?(error)
  ActiveSupport::Ractors.make_shareable(self, copy: false)
end

Instance Method Details

#attach_cause(error, cause) (private)

raise is the only way to set a cause.

[ GitHub ]

  
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy.rb', line 75

def attach_cause(error, cause)
  raise error, cause: cause
rescue error.class
  error
end

#capture_ivars(error) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy.rb', line 63

def capture_ivars(error)
  error.instance_variables.each_with_object({}) do |name, ivars|
    next if name == :@connection_pool

    value = error.instance_variable_get(name)
    ivars[name] = value.is_a?(Proc) ?
      ActiveSupport::Ractors.shareable_proc(&value) :
      ActiveSupport::Ractors.make_shareable(value)
  end
end

#exception(connection_pool: nil)

[ GitHub ]

  
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy.rb', line 32

def exception(connection_pool: nil)
  remote = remote_error
  error =
    if @ivars
      rebuilt = @error_class.allocate.exception(@message)
      @ivars.each { |name, value| rebuilt.instance_variable_set(name, value) }
      rebuilt.instance_variable_set(:@connection_pool, connection_pool) if rebuilt.is_a?(AdapterError)
      attach_cause(rebuilt, remote)
    else
      remote
    end
  error.set_backtrace(@backtrace + caller) if @backtrace
  error
end

#reconstructible?(error) ⇒ Boolean (private)

Arbitrary exceptions may carry unshareable or hidden state. Active Record errors have known state we can copy; otherwise only stateless non-system errors are safe to rebuild.

[ GitHub ]

  
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy.rb', line 57

def reconstructible?(error)
  return true if error.is_a?(ActiveRecordError)

  error.instance_variables.empty? && !error.is_a?(SystemCallError)
end

#remote_error

[ GitHub ]

  
# File 'activerecord/lib/active_record/connection_adapters/ractor_connection_handler/proxy.rb', line 47

def remote_error
  error = RemoteError.new(@error_class, @message)
  error.set_backtrace(@backtrace) if @backtrace
  @cause ? attach_cause(error, @cause.remote_error) : error
end