1

We recently implemented a read-replica in our Rails 6 application. We are only using it for specific transactions by wrapping them in a block:

ActiveRecord::Base.connected_to(role: :reading) do
  # read query here
end

In application_record.rb we have

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

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

In our database.yaml we have:

production:
  primary:
    url: <%= ENV['DATABASE_CONNECTION_POOL_URL'] || ENV['DATABASE_URL'] %>
    pool: <%= ENV["DB_POOL"] || ENV['RAILS_MAX_THREADS'] || 5 %>
    reaping_frequency: <%= ENV["REAPING_FREQUENCY"] || 10 %>
    adapter: postgresql
    advisory_locks: false
  primary_replica:
    url: <%= ENV['REPLICA_DATABASE_POOL_URL'] %>
    pool: <%= ENV["DB_POOL"] || ENV['RAILS_MAX_THREADS'] || 5 %>
    reaping_frequency: <%= ENV["REAPING_FREQUENCY"] || 10 %>
    adapter: postgresql
    advisory_locks: false
    replica: true

RAILS_MAX_THREADS is set to 12 and REAPING_FREQUENCY is set to 10 on our environment.

Whenever we start calling a background jobs (via sidekiq) and our queue builds up we start getting failures that are throwing the error: ActiveRecord::ConnectionTimeoutError: could not obtain a connection from the pool within 5.000 seconds (waited 5.366 seconds); all pooled connections were in use

I cannot replicate this behavior in our mirrored development environments even if I queue up a bunch of jobs and workers to process them. I'm at a loss on what I am missing with our connection pooling config. Most of the documentation I've read for rails 6 says we don't need to set any specific config for pooling in sidekiq.rb or puma.rb

We are running ruby 3.1.2 and rails 6.1.6

Any help or guidance here would be greatly appreciated.

hummmingbear
  • 2,294
  • 5
  • 25
  • 42
  • How do you start sidekiq? Are you sure that when sidekiq is started that it is receiving all the environment variables that are specified in your database.yml file? If you have sidekiq print out `Rails.configuration.database_configuration` on startup does it show what you expect it to show? – anothermh Feb 09 '23 at 20:50
  • We start sidekiq in our Procfile with `bundle exec sidekiq -c ${SIDEKIQ_RAILS_CONCURRENCY:-6} -q default`. It definitely gets our ENVs as many other things would be failing if not. I will see if I can get a logging statement of `Rails.configuration.database_configuration` in a job. `SIDEKIQ_RAILS_CONCURRENCY` is set to 12 in production – hummmingbear Feb 09 '23 at 21:06
  • You can add `puts Rails.configuration.database_configuration` to `config/initializers/sidekiq.rb` to have it print during startup rather than modifying a job to print it. – anothermh Feb 09 '23 at 21:34

1 Answers1

0

Our concurrency/threading needed to be tuned. Had nothing to do with the replica. This video was extremely straight forward and resolved our issue: https://www.youtube.com/watch?v=XOfELjqm188

hummmingbear
  • 2,294
  • 5
  • 25
  • 42