2010-04-10 3 views
20

У меня есть сайт запущенного приложения рельсов и Resque рабочих работают в режиме производства, на Ubuntu 9.10, Rails 2.3.4, рубин-е-е 2010,01, PostgreSQL 8.4.2Rails Resque рабочих завершаться PGError: сервер закрыл соединение неожиданно

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

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

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

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

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

ответ

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

+6

Спасибо, поэтому я просто добавил hook: Resque.after_fork = Proc.new {ActiveRecord :: Base.install_connection} –

+1

У меня может возникнуть аналогичная проблема. Можете ли вы рассказать мне, как и где вы добавили «крючок»? –

+0

нижняя ссылка сломана – botbot

9

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

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

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

+0

my: задача установки должна была находиться внутри : задача resque. (Не resque: настройка внутри: resque!) Из-за этого сначала это не сработало для меня. Я просто хотел сказать людям, чтобы они дважды проверяли задачу. – scaryguy

0

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

PassengerSpawnMethod conservative 
0

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

Смежные вопросы