Rails has added support for automatic database connection switching from primary to the replica


We discussed in one of our recent blog post, on how to connect to multiple databases and perform manual connection switching. Today, we are going to discuss how Rails can help you automatically switch connections from the primary to the replica.

Let’s once again revisit how the database.yml will look like for the primary and the read replica configuration.

default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

development:
  primary:
    <<: *default
    database: my_primary_database
    user: root

  replica:
    <<: *default
    database: my_primary_database
    user: root_readonly
    replica: true

The model to use the database connections will be configured as below:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true

  connects_to database: { writing: :primary, reading: :replica }
end

Rails has also introduced a middleware to automatically switch connections based on the HTTP verb. The following lines will have to be added to the application config.

config.active_record.database_resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver
config.active_record.database_resolver_context = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session

The requests are routed as follows:

  • The request is sent to the replica if the request is a read request (GET, HEAD) AND the last write to the database was made 2 seconds ago or more.
  • The request is sent to the primary if the request is a non-read request ( POST, DELETE, … ) OR the last write to the database was made less than 2 seconds ago.

The delay mentioned as 2 seconds is the default. It is required to allow the replica to catch up to the primary and prevent stale reads because of the replication lag.

It can be configured as below:

config.active_record.database_selector = { delay: 5.seconds }