2

There is a Rails 5 application that runs in Heroku; it has two DBs, a Primary and a Follower (read-only), the follower is the replica of the Primary. In some application areas, we use followers to get the data. Previously, rails didn't support Multi DB, so we used the Gem Octopus. However, they put it in maintenance mode as the Rails 6 supports the Multi DB.

We used different ways to access the follower db through octopus like:

class ApplicationRecord < ActiveRecord::Base
  self.abstract_class = true
end
class SetupController < ApplicationController
  around_action :select_follower

  def select_follower(&block)
    Octopus.using(ENV['FOLLOWER_DB'], &block)
  end

  def method1
   // enter code here
  end
end
@customer = Customer.using(FOLLOWER_DB).find(params[:id])
Octopus.using(:master) do
  SidekiqWorker.perform_async(param1, param2)
end

It was working fine and this has been running for more than 5 years.

Recently We have migrated our Rails application to Rails 6 from 5 and we replaced the octopus with multi DB setup.

database.yml

production:
 primary:
  <<: *default
  url: <%= ENV['DATABASE_URL'] %>
 secondary:
  <<: *default
  url: <%= ENV['FOLLOWER_DATABASE_URL'] %>
  migrations_paths: db/secondary_migrate

app/models/application_record.rb

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

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

app/models/secondary_application_record.rb

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

  connects_to database: { writing: :secondary, reading: :secondary }
end

Then when we try to access the follower as we done the same way with octopus, like

class DashboardController < ApplicationController

  around_action :select_secondary_db

  def select_secondary_db(&block)
    SecondaryApplicationRecord.connected_to(role: :reading, &block)
  end

  def method1
   // enter code here
  end
end

or

SecondaryApplicationRecord.connected_to(role: :reading) do
  Customer.find_by_id(params[:id])
end

In all this new way, the logs shows the query runs in primary db, nothing runs through follower/secondary DB. What could be the case that run always through primary?

1
  • I am assuming Customer inherits from ApplicationRecord and as such it uses the reading role defined. You could try using the sharding syntax instead. Docs. It says it is for horizontal sharding but it seems like it should work fine for vertical sharding. Commented Dec 23, 2024 at 18:18

1 Answer 1

0

I agree with @engineersmnky that your issue is one of inheritance.

I don't think you need horizontal sharding. Just use the context switching discussed in the docs:

ActiveRecord::Base.connected_to(role: :reading) do
  Customer.find_by_id(params[:id])
end

I've personally never seen a separate implementation of a secondary abstract class. This could work if you always want Customer to read from the follower:

class Customer < SecondaryApplicationRecord
end

But this could be problematic if that id was just written to the primary and the follower hasn't written it yet.

Note that Rails can provide intelligent context-aware switching, so you may be fine-tuning more than you need:

If the application is receiving a POST, PUT, DELETE, or PATCH request the application will automatically write to the writer database. For the specified time after the write, the application will read from the primary. For a GET or HEAD request the application will read from the replica unless there was a recent write.

If your Customer.find_by_id(params[:id]) is in a controller GET action like index, then Rails would automatically read from the :reading follower (if the specified time after a write has elapsed).

When not working in controllers, my team just uses the manual context switching as needed.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.