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! в методах почтовой программы, чтобы обеспечить соединение.