Как правильно работать с БД и пулом соединений с БД?

В моем коде я открываю БД при запуске программы и передаю переменную db другим методам. Я считаю, что это глупо и неправильно. Но что мне делать? Должен ли я открывать соединение с БД в каждом методе? Но этот путь тоже не выглядит правильным... И у меня много ошибок: DB::ConnectionRefused, DB::PoolTimeout, DB::PoolRetryAttemptsExceeded Значит, что-то не так с моим кодом.

def main_meth
db = DB.open("postgres://blabla@localhost:5432/bla?retry_attempts=8&retry_delay=3&max_pool_size=50&max_idle_pool_size=10&checkout_timeout=0.1") # there is always same story with or without params.
begin

db.scalar("")
...
another_meth(params, db)

channel = Channel(Nil).new(20)
    groups.each do |group|
      spawn one_more_meth(group, channel, db)
    end
    groups.size.times { channel.receive }

 ensure
      db.close
    end
end

def another_meth(p, db)
deeper_meth(db)
end

def one_more_meth(group, channel, db)
...
db.query_all
...
channel.send(nil)
end

person nobilik    schedule 16.03.2017    source источник
comment
Должно быть правильно передавать одну БД по всей программе: она обрабатывает пул внутри себя. Какие-либо запросы вообще работают или ошибки возникают только при выполнении большого количества запросов? Если нет, работает ли он с другого языка, используя тот же URL-адрес подключения?   -  person Stephie    schedule 16.03.2017
comment
Это происходит с большим количеством запросов. Да, на кристалле есть 10 независимых программ + 1 приложение для рельсов. Но у меня на странице установлено максимум 2000 подключений.   -  person nobilik    schedule 16.03.2017
comment
Но на моем локальном компьютере у меня такие же ошибки только с одним запущенным приложением.   -  person nobilik    schedule 16.03.2017
comment
Но это не происходит при всех запросах от crystal, я прав?   -  person Stephie    schedule 16.03.2017
comment
Да Вы. Похоже, что соединения, выпущенные пулом соединений, слишком медленны.   -  person nobilik    schedule 16.03.2017
comment
Я думаю, что это ошибка или что-то, связанное с дальнейшим расследованием. Я предлагаю создать проблему здесь: github.com/crystal-lang/crystal-db /вопросы   -  person Stephie    schedule 16.03.2017
comment
У меня есть предположение, что на моем локальном компьютере это может быть из-за того, что жесткий диск слишком медленный (мой новый комп сломан). И из-за этого я открываю и закрываю БД в каждом способе освобождения соединения. Но на производстве это может генерировать отказ в соединении.   -  person nobilik    schedule 17.03.2017
comment
Я столкнулся с похожей проблемой и обнаружил, что при выполнении db.query вы должны либо использовать блок: db.query("") do |rs|; end, либо закрыть набор результатов: rs = db.query("");rs.close   -  person fridgerator    schedule 18.03.2017
comment
@fridgerator Спасибо за совет. Но я не использую db.query таким образом. Я использую db.scalar, db.exec, db.query_all и Class.from_rs(db.query). Насколько я понимаю, ни один из этих запросов не должен быть закрыт вручную.   -  person nobilik    schedule 19.03.2017
comment
Class.from_rs(db.query "") может не закрыть результирующий набор. Вы можете попробовать сохранить запрос в переменную и после from_rs закрыть его: rs = db.query("");Class.from_rs(rs);rs.close   -  person fridgerator    schedule 20.03.2017
comment
@fridgerator Похоже, ты прав! Спасибо. Вы можете добавить ответ, я приму его.   -  person nobilik    schedule 20.03.2017


Ответы (1)


Я столкнулся с аналогичной проблемой и обнаружил, что при выполнении db.query вы должны убедиться, что:

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

rs = db.query("")
Class.from_rs(rs)
rs.close

ИЛИ использовать блок

db.query("") do |rs|
    Class.from_rs(rs)
end
person fridgerator    schedule 20.03.2017
comment
Вот новое исправление, которое делает rs.close ненужным github.com/crystal-lang/ кристалл-дб/коммит/ - person nobilik; 21.03.2017
comment
это здорово, здорово! - person fridgerator; 21.03.2017