123456789_123456789_123456789_123456789_123456789_

Class: ActiveRecord::Middleware::DatabaseSelector::Resolver

Do not use. This class is for internal use only.

Overview

The Resolver class is used by the ::ActiveRecord::Middleware::DatabaseSelector middleware to determine which database the request should use.

To change the behavior of the Resolver class in your application, create a custom resolver class that inherits from Resolver and implements the methods that need to be changed.

By default the Resolver class will send read traffic to the replica if it’s been 2 seconds since the last write.

Constant Summary

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Constructor Details

.new(context, options = {}) ⇒ Resolver

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 26

def initialize(context, options = {})
  @context = context
  @options = options
  @delay = @options && @options[:delay] ? @options[:delay] : SEND_TO_REPLICA_DELAY
  @instrumenter = ActiveSupport::Notifications.instrumenter
end

Class Method Details

.call(context, options = {})

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 22

def self.call(context, options = {})
  new(context, options)
end

Instance Attribute Details

#context (readonly)

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 33

attr_reader :context, :delay, :instrumenter

#delay (readonly)

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 33

attr_reader :context, :delay, :instrumenter

#instrumenter (readonly)

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 33

attr_reader :context, :delay, :instrumenter

#read_from_primary?Boolean (readonly, private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 78

def read_from_primary?
  !time_since_last_write_ok?
end

#time_since_last_write_ok?Boolean (readonly, private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 86

def time_since_last_write_ok?
  Time.now - context.last_write_timestamp >= send_to_replica_delay
end

Instance Method Details

#read(&blk)

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 35

def read(&blk)
  if read_from_primary?
    read_from_primary(&blk)
  else
    read_from_replica(&blk)
  end
end

#read_from_primary(&blk) (readonly, private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 56

def read_from_primary(&blk)
  ActiveRecord::Base.connected_to(role: ActiveRecord.writing_role, prevent_writes: true) do
    instrumenter.instrument("database_selector.active_record.read_from_primary", &blk)
  end
end

#read_from_replica(&blk) (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 62

def read_from_replica(&blk)
  ActiveRecord::Base.connected_to(role: ActiveRecord.reading_role, prevent_writes: true) do
    instrumenter.instrument("database_selector.active_record.read_from_replica", &blk)
  end
end

#reading_request?(request) ⇒ Boolean

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 51

def reading_request?(request)
  request.get? || request.head?
end

#send_to_replica_delay (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 82

def send_to_replica_delay
  delay
end

#update_context(response)

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 47

def update_context(response)
  context.save(response)
end

#write(&blk)

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 43

def write(&blk)
  write_to_primary(&blk)
end

#write_to_primary (private)

[ GitHub ]

  
# File 'activerecord/lib/active_record/middleware/database_selector/resolver.rb', line 68

def write_to_primary
  ActiveRecord::Base.connected_to(role: ActiveRecord.writing_role, prevent_writes: false) do
    instrumenter.instrument("database_selector.active_record.wrote_to_primary") do
      yield
    ensure
      context.update_last_write_timestamp
    end
  end
end