为给定的Resque队列定义ActiveRecord连接

时间:2013-04-16 18:57:00

标签: activerecord heroku resque

问题域

Heroku Cedar堆栈,包含多个数据库。主数据库的RDS和第二个Analytics数据库的Postgres。服务器使用读/写RDS Postgres数据库运行。在不同环境中运行的每晚rake任务需要在RDS数据库的只读从属服务器中运行特定的Resque队列。

Postgres数据库连接

对于记录,Postgres数据库中的所有模型都包括:

module Trove::PostgresConnection
  def self.included(base)
    base.class_eval do
      …set up Postgres database
    end
  end
end

这很好用,并且作为注入每个类的模块,不会因为对ActiveRecord :: Base.connection的任何更改而被压扁

MySQL连接

使用Heroku RDS插件定义。连接到读/写生产数据库。不幸的是,无论环境如何都使用此连接。因此,使用RAILS_ENV=analytics rake some:task在Heroku上运行rake任务不会将此连接用于ActiveRecord::Base

analytics:
  adapter: mysql2
  encoding: utf8
  database: dbase
  username: uname
  password: pword
  host: read-only.uri.on.amazonaws.com
  reconnect: true
  port: 3306

相反,它使用RDS连接中提供的连接字符串:

puts Rails.env
-> 'analytics'
puts SomeModel.connection_config[:host]
-> read-write.uri.on.amazonaws.com

我花了一些时间来弄清楚这一点。自我注意:不要只看环境,看看数据库主机。

当前解决方法

# Perform an operation using another database connection in ActiveRecord
module SwapConnection

  def with_connection_to(config, &block)
    ActiveRecord::Base.connection.disconnect!
    ActiveRecord::Base.establish_connection(config)

    yield

  end
end

require 'swap_connection'
class TroveCalculations
  @queue = :trove_queue

  def self.perform(class_name, id)
    SwapConnection.with_connection_to(Rails.env) do
      Do something in a given queue
    end
  end
end

期望的能力

在Procfile中有这样的东西

troveworker:    env RAILS_ENV=analytics QUEUE=trove_queue bundle exec rake resque:work

其中实际上使用该工作者的分析database.yml配置。我们目前使用此Procfile运行我们的服务器,但它仍然使用RDS数据库。

4 个答案:

答案 0 :(得分:2)

为了扩展我对这个问题的评论,我的意思是为你的数据库添加一个“Heroku方式”的配置,然后在你的Procfile中为那个将处理该队列上的工作的一个工人引用它。

使用新名称添加配置/环境变量以及您需要的数据库配置:

heroku config:add ANALYTICS_DB=postgres://some_url

在你的Procfile中,基于你想要的例子:

troveworker:    env DATABASE_URL=$(ANALYTICS_DB) QUEUE=trove_queue \
                bundle exec rake resque:work

你必须使用不同的配置为每个队列使用单独的worker,但配置将至少不在代码中。

答案 1 :(得分:1)

我只玩Heroku,但我认为数据库连接信息被Heroku工具根据heroku工具带指定的环境变量覆盖。

答案 2 :(得分:1)

这里的问题是Heroku生成自己的database.yml文件:https://devcenter.heroku.com/articles/ruby-support#build-behavior

通过使用Amazon RDS插件,Heroku设置了DATABASE_URL环境变量。您可以通过从应用程序目录的根目录运行以下内容来查看其内容: heroku config

此外,从Rails 3.2开始,它将使用DATABASE_URL env var(如果设置)而不是database.yml文件:

https://github.com/mperham/sidekiq/issues/503#issuecomment-11862427

最简单的解决方法可能是:

  1. 使用Postgres连接字符串创建一个名为DATABASE_URL_ANALYTICS的env var: heroku config:add DATABASE_URL_ANALYTICS=postgres://xxxxxxxxxxxx

  2. 在rake文件的开头(可能发生任何rails初始化之前),添加: ENV['DATABASE_URL'] = ENV['DATABASE_URL_ANALYTICS'] if Rails.env.analytics?

答案 3 :(得分:0)

更新:不工作。 (原始答案留作文件)

这就是我们解决它的方式:

Procfile:

troveworker:    env RAILS_ENV=analytics QUEUE=trove_queue rake trove:worker

LIB /任务/ trove.rake:

desc 'Start the Resque workers in the proper environment'
task :worker do
  SwapConnection.with_connection_to Rails.env do
    Rake::Task['resque:work'].invoke
  end
end

此解决方案也为我们解决了一些其他问题,并且工作得非常好。谢谢大家。