Работники Rails Resque завершают работу с PGError: сервер неожиданно закрыл соединение - PullRequest
20 голосов
/ 10 апреля 2010

У меня есть сайт, на котором запущено приложение rails, и работники resque, работающие в производственном режиме, на Ubuntu 9.10, Rails 2.3.4, ruby-ee 2010.01, PostgreSQL 8.4.2

Работники постоянно выдавали ошибки: PGError: сервер неожиданно закрыл соединение.

Мое лучшее предположение состоит в том, что основной процесс восстановления устанавливает соединение с БД (например, authlogic делает это при использовании User.acts_as_authentic), загружая классы приложений rails, и это соединение разрывается в процессе fork () ed (при выходе?), так что следующие разветвленные дети получат неработающий глобальный ActiveRecord :: Base.connection

Я мог бы воспроизвести очень похожее поведение с этим примером кода , имитирующим разветвление / обработку в resque worker. (AFAIK, пользователи libpq в любом случае рекомендуют воссоздавать соединения в разветвленном процессе, в противном случае это небезопасно)

Но странным является то, что когда я использую pgbouncer или pgpool-II вместо прямого соединения pgsql, такие ошибки не появляются.

Итак, вопрос в том, куда и как мне копать, чтобы узнать, почему он не работает для простого соединения и работает с пулами соединений? Или разумный обходной путь?

Ответы [ 5 ]

55 голосов
/ 02 апреля 2011

После небольшого исследования / проб и ошибок. Для тех, кто сталкивается с той же проблемой. Чтобы уточнить, что упоминал gc.

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

Над кодом должен быть помещен в:

Например:

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"

Надеюсь, это поможет кому-то, так же, как и мне.

12 голосов
/ 10 апреля 2010

Когда я создал Нестор , у меня была такая же проблема. Решение состояло в том, чтобы восстановить соединение в разветвленном процессе. См. Соответствующий код на http://github.com/francois/nestor/blob/master/lib/nestor/mappers/rails/test/unit.rb#L162

Из моего очень ограниченного взгляда на код Resque, я считаю, что вызов #establish_connection должен быть сделан прямо здесь:

10 голосов
/ 10 апреля 2010

Вы не можете передать ссылку libpq через fork () (или в новый поток), если ваше приложение не очень внимательно следит за тем, чтобы не использовать его конфликтующими способами. (Например, мьютекс вокруг каждой попытки использовать его, и вы никогда не должны закрывать его). Это одинаково как для прямых подключений, так и для использования pgbouncer. Если это сработало в pgbouncer, то по какой-то причине пропало условие гонки, и это в конечном итоге сломалось.

Если ваша программа использует разветвление, вы должны создать соединение после форка.

0 голосов
/ 28 апреля 2013

У меня была эта проблема со всеми моими классами Mailer, и мне нужно было вызвать ActiveRecord::Base.verify_active_connections! внутри методов mailer, чтобы убедиться, что было установлено соединение.

0 голосов
/ 24 сентября 2012

Измените конфигурацию Apache и добавьте

PassengerSpawnMethod conservative
...