class ReplicaPools::ConnectionProxy

Attributes

current[RW]
current_pool[RW]
leader[RW]
leader_depth[RW]
replica_pools[RW]

Public Class Methods

generate_safe_delegations() click to toggle source
# File lib/replica_pools/connection_proxy.rb, line 12
def generate_safe_delegations
  ReplicaPools.config.safe_methods.each do |method|
    self.define_method(method) do |*args, &block|
      route_to(current, method, *args, &block)
    end unless instance_methods.include?(method)
  end
end
get_connection_config_method_name() click to toggle source
# File lib/replica_pools/connection_proxy.rb, line 39
def self.get_connection_config_method_name
  # 6.1 supports current.connection_config
  # but warns of impending deprecation in 6.2
  if ActiveRecord::VERSION::STRING.to_f >= 6.1
    :connection_db_config
  else
    :connection_config
  end
end
new(leader, pools) click to toggle source
# File lib/replica_pools/connection_proxy.rb, line 21
def initialize(leader, pools)
  @leader        = leader
  @replica_pools = pools
  @leader_depth  = 0
  @current_pool  = default_pool

  if ReplicaPools.config.defaults_to_leader
    @current = leader
  else
    @current = current_replica
  end

  # this ivar is for ConnectionAdapter compatibility
  # some gems (e.g. newrelic_rpm) will actually use
  # instance_variable_get(:@config) to find it.
  @config = current.send(ReplicaPools::ConnectionProxy.get_connection_config_method_name)
end

Public Instance Methods

current_replica() click to toggle source
# File lib/replica_pools/connection_proxy.rb, line 82
def current_replica
  current_pool.current
end
next_replica!() click to toggle source
# File lib/replica_pools/connection_proxy.rb, line 77
def next_replica!
  return if within_leader_block?
  self.current = current_pool.next
end
transaction(...) click to toggle source
# File lib/replica_pools/connection_proxy.rb, line 73
def transaction(...)
  with_leader { leader.transaction(...) }
end
with_leader() { || ... } click to toggle source
# File lib/replica_pools/connection_proxy.rb, line 59
def with_leader
  raise LeaderDisabled.new if ReplicaPools.config.disable_leader

  last_conn = self.current
  self.current = leader
  self.leader_depth += 1
  yield
ensure
  if last_conn
    self.leader_depth = [leader_depth - 1, 0].max
    self.current = last_conn
  end
end
with_pool(pool_name = 'default') { || ... } click to toggle source
# File lib/replica_pools/connection_proxy.rb, line 49
def with_pool(pool_name = 'default')
  last_conn, last_pool = self.current, self.current_pool
  self.current_pool = replica_pools[pool_name.to_sym] || default_pool
  self.current = current_replica unless within_leader_block?
  yield
ensure
  self.current_pool = last_pool
  self.current      = last_conn
end

Protected Instance Methods

default_pool() click to toggle source
# File lib/replica_pools/connection_proxy.rb, line 88
def default_pool
  replica_pools[:default] || replica_pools.values.first
end
method_missing(method, *args, **kwargs, &block) click to toggle source

Proxies any unknown methods to leader. Safe methods have been generated during ‘setup!`. Creates a method to speed up subsequent calls.

# File lib/replica_pools/connection_proxy.rb, line 95
def method_missing(method, *args, **kwargs, &block)
  self.class.define_method(method) do |*args, **kwargs, &block|
    route_to(leader, method, *args, **kwargs, &block).tap do
      if %i[insert delete update].include?(method)
        leader.retrieve_connection.clear_query_cache
      end
    end
  end
  send(method, *args, **kwargs, &block)
end
route_to(conn, method, *args, **keyword_args, &block) click to toggle source
# File lib/replica_pools/connection_proxy.rb, line 110
def route_to(conn, method, *args, **keyword_args, &block)
  raise ReplicaPools::LeaderDisabled.new if ReplicaPools.config.disable_leader && conn == leader
  conn.retrieve_connection.send(method, *args, **keyword_args, &block)
rescue => e
  ReplicaPools.log :error, "Error during ##{method}: #{e}"
  log_proxy_state
  raise e
end
within_leader_block?() click to toggle source
# File lib/replica_pools/connection_proxy.rb, line 106
def within_leader_block?
  leader_depth > 0
end

Private Instance Methods

log_proxy_state() click to toggle source
# File lib/replica_pools/connection_proxy.rb, line 121
def log_proxy_state
  ReplicaPools.log :error, "Current Connection: #{current}"
  ReplicaPools.log :error, "Current Pool Name: #{current_pool.name}"
  ReplicaPools.log :error, "Current Pool Members: #{current_pool.replicas}"
  ReplicaPools.log :error, "Leader Depth: #{leader_depth}"
end