class ActiveRecord::Middleware::DatabaseSelector

The DatabaseSelector Middleware provides a framework for automatically swapping from the primary to the replica database connection. Rails provides a basic framework to determine when to swap and allows for applications to write custom strategy classes to override the default behavior.

The resolver class defines when the application should switch (i.e. read from the primary if a write occurred less than 2 seconds ago) and a resolver context class that sets a value that helps the resolver class decide when to switch.

Rails default middleware uses the request's session to set a timestamp that informs the application when to read from a primary or read from a replica.

To use the DatabaseSelector in your application with default settings add the following options to your environment config:

config.active_record.database_selector = { delay: 2.seconds }
config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session

New applications will include these lines commented out in the production.rb.

The default behavior can be changed by setting the config options to a custom class:

config.active_record.database_selector = { delay: 2.seconds }
config.active_record.database_resolver = MyResolver
config.active_record.database_resolver_context = MyResolver::MySession

Attributes

context_klass[R]
options[R]
resolver_klass[R]

Public Class Methods

new(app, resolver_klass = nil, context_klass = nil, options = {}) click to toggle source
# File lib/active_record/middleware/database_selector.rb, line 38
def initialize(app, resolver_klass = nil, context_klass = nil, options = {})
  @app = app
  @resolver_klass = resolver_klass || Resolver
  @context_klass = context_klass || Resolver::Session
  @options = options
end

Public Instance Methods

call(env) click to toggle source

Middleware that determines which database connection to use in a multiple database application.

# File lib/active_record/middleware/database_selector.rb, line 49
def call(env)
  request = ActionDispatch::Request.new(env)

  select_database(request) do
    @app.call(env)
  end
end

Private Instance Methods

reading_request?(request) click to toggle source
# File lib/active_record/middleware/database_selector.rb, line 72
def reading_request?(request)
  request.get? || request.head?
end
select_database(request, &blk) click to toggle source
# File lib/active_record/middleware/database_selector.rb, line 58
def select_database(request, &blk)
  context = context_klass.call(request)
  resolver = resolver_klass.call(context, options)

  response = if reading_request?(request)
    resolver.read(&blk)
  else
    resolver.write(&blk)
  end

  resolver.update_context(response)
  response
end