简体   繁体   中英

Sidekiq & Clock Background Task On Redis, Rails, Heroku Only Updating Some

I am running a background task on many records with Rails, Sidekiq, Redis, and Clockwork on Heroku, but I keep getting this error on many of the records it's trying to update with an API:

ActiveRecord::ConnectionTimeoutError: could not obtain a database connection within 5.000 seconds

Here are my files:

Unicorn:

worker_processes Integer(ENV["WEB_CONCURRENCY"] || 3)
timeout 15
preload_app true

before_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn master intercepting TERM and sending myself QUIT instead'
    Process.kill 'QUIT', Process.pid
  end

  if defined?(ActiveRecord::Base)
    ActiveRecord::Base.connection.disconnect!
  end
end

after_fork do |server, worker|
  Signal.trap 'TERM' do
    puts 'Unicorn worker intercepting TERM and doing nothing. Wait for master to send QUIT'
  end

  if defined?(ActiveRecord::Base)
    config = Rails.application.config.database_configuration[Rails.env]
    config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
    config['pool']            = ENV['DB_POOL'] || 5
    ActiveRecord::Base.establish_connection(config)
  end
end

Database:

production:
  adapter: postgresql
  encoding: unicode
  database: production
  pool: 25
  timeout: 10000

Clock:

every(24.hours, 'Update') do
  sites = Site.order(:id).pluck(:id)
  Site.each do |site|
    UpdatePosts.perform_async(site)
  end
end

UpdatePosts

class UpdatePosts
    include Sidekiq::Worker
    sidekiq_options retry: false

    def perform(site_id)
    ...
    end
end

The error you're seeing is caused by more threads trying to obtain a connection from the ActiveRecord connection pool than there are connections in the pool. When a thread asks for a connection, but one isn't free within the 5 second timeout, the error you see is raised.

In Sidekiq, there are a larger number of worker threads than the default ActiveRecord pool size. This causes errors like this under load.

You can adjust the DB pool size to match the number of Sidekiq threads in your config/initializers/sidekiq.rb file using code like this:

Sidekiq.configure_server do |config|
  if(database_url = ENV['DATABASE_URL'])
    pool_size = Sidekiq.options[:concurrency] + 2
    ENV['DATABASE_URL'] = "#{database_url}?pool=#{pool_size}"
    ActiveRecord::Base.establish_connection
  end
end

Although you have attempted to increase the pool_size in your database.yml file, this configuration is overwritten on deploy in Heroku and driven entirely by the DATABASE_URL environment variable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM