Rails Resque работают с PGError: сервер неожиданно закрыл соединение
У меня есть приложение для работы с rails на сайте и resque, работающие в режиме производства, на Ubuntu 9.10, Rails 2.3.4, ruby-ee 2010.01, PostgreSQL 8.4.2
Рабочие постоянно поднимали ошибки: PGError: сервер неожиданно закрыл соединение.
Мое лучшее предположение заключается в том, что процесс master resque устанавливает соединение с db (например, authlogic делает это при использовании User.acts_as_authentic) при загрузке классов приложений rails и что соединение становится поврежденным в процессе fork() ed (при выходе?), поэтому следующие раздвоенные дети получают вид сломанной глобальной ActiveRecord:: Base.connection
Я мог бы воспроизвести очень похожее поведение с этим образцом кода, имитирующим fork/processing в resque worker. (AFAIK, пользователи libpq рекомендовали воссоздать соединения в forked-процессе в любом случае, в противном случае это небезопасно)
Но, что странно, когда я использую pgbouncer или pgpool-II вместо прямого подключения pgsql, такие ошибки не отображаются.
Итак, вопрос в том, где и как я должен копать, чтобы узнать, почему он сломан для простого соединения и работает с пулами подключений? Или разумное обходное решение?
Ответы
Ответ 1
Когда я создал 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
После нескольких исследований/проб и ошибок. Для тех, кто сталкивается с одной и той же проблемой. Чтобы уточнить, что упомянуто 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"
Надеюсь, это поможет кому-то, насколько это было для меня.
Ответ 3
Вы не можете передать ссылку libpq через fork() (или в новый поток), если ваше приложение не очень внимательно следит за тем, чтобы не использовать его конфликтующими способами. (Например, мьютекс вокруг каждой попытки использовать его, и вы никогда не должны его закрывать). Это то же самое для прямых подключений и использования pgbouncer. Если это сработало в pgbouncer, это было чистой удачей в том, что у вас какое-то время не было условия гонки, и он в конечном итоге сломается.
Если ваша программа использует forking, вы должны создать соединение после fork.
Ответ 4
Измените конфигурацию Apache и добавьте
PassengerSpawnMethod conservative
Ответ 5
У меня была эта проблема со всеми моими классами Mailer, и мне нужно было вызвать ActiveRecord::Base.verify_active_connections!
в методах почтовой программы, чтобы обеспечить соединение.