我在Ubuntu 9.10,Rails 2.3.4,ruby-ee 2010.01,PostgreSQL 8.4.2
上有运行rails应用程序和resque worker在生产模式下运行的站点工作人员经常出错:PGError:服务器意外关闭了连接。
我最好的猜测是主resque进程建立与db的连接(例如authlogic在使用User.acts_as_authentic时执行此操作),同时加载rails app类,并且该连接在fork()ed进程中损坏(退出?),所以下一个分叉的孩子会得到一些破碎的全局ActiveRecord :: Base.connection
我可以在resque worker中使用这个sample code模仿fork /处理来重现非常类似的行为。 (AFAIK,libpq的用户建议无论如何都要在forked进程中重新创建连接,否则它不安全)
但是,奇怪的是当我使用pgbouncer或pgpool-II而不是直接pgsql连接时,不会出现这样的错误。
所以,问题是我应该在哪里以及如何挖掘以找出为什么它被破坏以进行普通连接并且正在使用连接池?还是合理的解决方法?
答案 0 :(得分: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"
希望这对某人有所帮助,就像对我一样。
答案 1 :(得分:12)
当我创建Nestor时,我遇到了同样的问题。解决方案是在分叉进程中重新建立连接。请参阅http://github.com/francois/nestor/blob/master/lib/nestor/mappers/rails/test/unit.rb#L162
上的相关代码从我的非常看看Resque代码,我相信应该在这里调用#establish_connection:https://github.com/resque/resque/blob/master/lib/resque/worker.rb#L123
答案 2 :(得分:10)
您不能通过fork()(或新线程)传递libpq引用,除非您的应用程序非常小心地不以冲突的方式使用它。 (比如,围绕每次尝试使用它的互斥锁,你必须永远不要关闭它)。对于直接连接和使用pgbouncer,这都是相同的。如果它在pgbouncer中有效,那么由于某种原因错过了竞争条件,这真的很幸运,最终会破裂。
如果您的程序使用分叉,则必须在分叉后创建连接。
答案 3 :(得分:0)
更改Apache配置并添加
PassengerSpawnMethod conservative
答案 4 :(得分:0)
我的所有Mailer类都遇到此问题,我需要在邮件程序方法中调用ActiveRecord::Base.verify_active_connections!
以确保建立连接。