Rails Resque工作者出现PGError错误:服务器意外关闭了连接。

20

我有一个运行着Rails应用程序和Resque工作进程的网站,在Ubuntu 9.10,Rails 2.3.4,ruby-ee 2010.01和PostgreSQL 8.4.2上以生产模式运行。

工作进程不断抛出错误:PGError: server closed the connection unexpectedly。

我最好的猜测是,主Resque进程在加载Rails应用程序类时建立与数据库的连接(例如,当使用User.acts_as_authentic时,Authlogic会这样做),而该连接在fork()的进程中变得损坏(在退出时?),因此下一个fork()的子进程获得了一种有问题的全局ActiveRecord:: Base.connection。

我可以使用这个示例代码模拟Resque工作程序中的fork /处理,从而复制非常相似的行为。 (据我所知,libpq用户建议在forked进程中重新创建连接,否则不安全)

但是,奇怪的是,当我使用pgbouncer或pgpool-II而不是直接pgsql连接时,这些错误不会出现。

因此,问题是我应该在哪里和如何挖掘才能找出为什么直接连接出了问题,而连接池却可以正常工作?或者合理的解决方法?

5个回答

55

经过一番研究和尝试,对于那些遇到同样问题的人来说,为了澄清gc提到的内容。

Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection }

以上代码应该放置在:/lib/tasks/resque.rake 中。

例如:

require 'resque/tasks'

task "resque:setup" => :environment do
  ENV['QUEUE'] = '*'

  Resque.after_fork do |job|
    ActiveRecord::Base.establish_connection
  end

end

desc "Alias for resque:work (To run workers on Heroku)"
task "jobs:work" => "resque:work"

希望这能像它对我一样,为其他人提供帮助。


6
你是位绅士和学者,肯定为我省去了一些麻烦。 - Jimmy
1
这很完美!但是你可能想要删除 ENV['QUEUE'] 这一行,因为它会通过将队列设置为 * 来破坏生成任何特定于队列的工作进程。 - nessur
我的 :setup 任务应该在 :resque 任务内部。不是在 :resque 里面的 :setup!因为这个原因,一开始这对我没有起作用。我只想告诉大家要仔细检查任务继承。 - scaryguy

12

6
谢谢,我只是简单地添加了钩子:Resque.after_fork = Proc.new { ActiveRecord::Base.establish_connection }。 - gc.
1
我可能面临类似的问题。你能告诉我你是如何在哪里添加“hook”的吗? - Christian Fazzini
底部链接已损坏 - botbot

10

如果你的应用程序在fork()(或新线程)中传递了一个libpq引用,除非你的应用程序非常小心地确保不以冲突的方式使用它(例如:在每次尝试使用它时都加互斥锁,并且不能关闭它),否则会出现问题。无论是直接连接还是使用pgbouncer,情况都是一样的。如果在pgbouncer中起作用,那只是因为碰巧避免了某种竞态条件而已,但最终也会出现问题。

如果你的程序使用forking,必须在fork之后创建连接。


0

更改Apache配置并添加

PassengerSpawnMethod conservative

0

我在所有的Mailer类中都遇到了这个问题,我需要在Mailer方法中调用ActiveRecord::Base.verify_active_connections!来确保建立连接。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接