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 }