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