LINUX.ORG.RU

RoR postgresql Thread количество подключений

 , ,


0

1

Есть сайтик на рор. Есть база postgresql которую этот сайтик использует. Для доступа к базе использую гем pg

ruby 2.1.1
pg-0.17.1
rails-4.0.4
postgresql-9.3.3

На сайте есть пара кусков кода которые могут выполняться очень долго в зависимости от внешних факторов и не всегда успешно. Я хочу ограничить время выполнение этих кусков кода. Для этого я запускаю их в Thread.new и жду окончание выполнения с помошью thread.join(5) В этих кусках кода есть пара запросов к базе(обычные запросы через модели по типу News.all), через некоторое время, на глаз где то после 30-50 обновлений страницы сайта у меня все отваливается, тестовый сервер рельсов начинает сыпать ошибками

ActiveRecord::ConnectionTimeoutError (could not obtain a database connection within 5.000 seconds (waited 5.000 seconds)): 
если попробовать подключиться к базе из консоли
$ psql -U postgres
psql: FATAL:  sorry, too many clients already
помогает только рестарт сервера рельсов

Без использования тредов все соответственно работает как надо.

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

Какие у кого есть мысли?

★★★★★

Последнее исправление: CYB3R (всего исправлений: 1)

могут выполняться очень долго в зависимости от внешних факторов и не всегда успешно.

так может вынести их в воркеры?

kelyar ★★★★★
()

А может стоит это делать на стороне БД?

anonymous
()
Ответ на: комментарий от TDrive

что-нибудь вроде delayed_job или sidekick, чтобы выполнять эти таски в фоне. тогда и таймауты не будут так сильно волновать.

kelyar ★★★★★
()
Ответ на: комментарий от Debasher

вынести работу с бд в отдельный тред?

На сколько я понял проблема в том, что используя запросы к базе внутри треда создаются новые подключения которые не закрываются. Пока, самое простое что придумал, это внутри треда открывать соединение с базой и делать запросы напрямую без моделей а потом самому закрывать соединения.

TDrive ★★★★★
() автор топика
Ответ на: комментарий от kelyar

что-нибудь вроде delayed_job или sidekick, чтобы выполнять эти таски в фоне. тогда и таймауты не будут так сильно волновать.

Там еще и результат работы этих долгих кусков кода нужно сразу показывать, просто если они слишком долго работают то лучше показать отсутствие результата чем заставлять пользователя ждать.

TDrive ★★★★★
() автор топика
Ответ на: комментарий от pi11

Попробуй connection pool. Например http://wiki.postgresql.org/wiki/Pgpool-II

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

TDrive ★★★★★
() автор топика

Укажи явным образом приемлемое количество соединений в пуле и таймаут в config/database.yml:

…
  pool: 10
  timeout: 5000
Apple-ch ★★
()
Ответ на: комментарий от TDrive

хотя если там можно настроить чтобы открытые подключения сами закрывались...

Это плохой путь, все коннекты к базе будут закрываться по таймауту.

Правильное решение - воркеры/менеджер очереди. Можно даже на вокруг postgresql notify сделать обработку, чтобы не городить IPC. Скрипт сайта добавляет задание в таблицу очереди и посылает NOTIFY, демон обработки очереди ловит это уведомление, получает необработанные задания из очереди, выполняет и кладёт обратно

disarmer ★★★
()
Ответ на: комментарий от disarmer

Правильное решение - воркеры/менеджер очереди. Можно даже на вокруг postgresql notify сделать обработку, чтобы не городить IPC. Скрипт сайта добавляет задание в таблицу очереди и посылает NOTIFY, демон обработки очереди ловит это уведомление, получает необработанные задания из очереди, выполняет и кладёт обратно

Да это не мой случай. Мне нужно или сразу показать результат пользователю или если расчет результата занимает много времени то показать болт. То есть результаты работы долгих кусков кода имеют значение только в контексте одного обновления страницы, а сами по себе они не сильно нужны.

TDrive ★★★★★
() автор топика
Ответ на: комментарий от TDrive

Таймаут указан, но не работает?

А вообще попробуй тогда в «тяжёлых» экшнах открывать отдельное соединение и в нём ставить отдельный таймаут.

Apple-ch ★★
()
Ответ на: комментарий от Apple-ch

А вообще попробуй тогда в «тяжёлых» экшнах открывать отдельное соединение и в нём ставить отдельный таймаут.

Ну вот я и решил просто соединение с базой открывать отдельно для каждого треда и самому их закрывать. Походу ничего лучше не придумать.

TDrive ★★★★★
() автор топика
Ответ на: комментарий от TDrive

Если ты не вызываешь establish_connection явным образом, то у тебя используется соединение из общего пула. Поэтому нет уверенности, что после смерти потока запрос не продолжает висеть.

Apple-ch ★★
()
Ответ на: комментарий от Apple-ch
conn = PG.connect
thread = Thread.new(conn) do |conn|
   conn.exec
end
thread.join(5)
thread.kill
conn.finish
TDrive ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.