1

我在 Heroku 上使用 Rails、Sidekiq、Redis 和 Clockwork 对许多记录运行后台任务,但在尝试使用 API 更新的许多记录上,我不断收到此错误:

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

这是我的文件:

独角兽:

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

数据库:

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

钟:

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

更新帖子

class UpdatePosts
    include Sidekiq::Worker
    sidekiq_options retry: false

    def perform(site_id)
    ...
    end
end
4

1 回答 1

3

您看到的错误是由于尝试从 ActiveRecord 连接池获取连接的线程多于池中的连接数造成的。当一个线程请求连接,但在 5 秒超时内没有空闲时,就会引发您看到的错误。

在 Sidekiq 中,工作线程的数量大于默认的 ActiveRecord 池大小。这会在负载下导致类似这样的错误。

您可以使用如下代码调整数据库池大小以匹配config/initializers/sidekiq.rb文件中的 Sidekiq 线程数:

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

尽管您已尝试增加文件pool_size中的database.yml,但此配置在 Heroku 中部署时会被覆盖,并且完全由DATABASE_URL环境变量驱动。

于 2014-02-17T17:04:49.700 回答