Ошибка пула соединений с базой данных Rails 4

У меня есть приложение rails, размещенное на NGINX и Puma. Примерно каждые 10 часов приложение становится непригодным для использования. Всякий раз, когда пользователь пытается подключиться, отображается следующее сообщение об ошибке:

Error during failsafe response: could not obtain a database connection within 5.000 seconds (waited 5.000 seconds)

Это продолжается до тех пор, пока приложение не будет перезапущено.

Я читал, что это связано с тем, что пул соединений с базой данных заполнен, поэтому в приложении rails должны создаваться потоки, которые не закрывают свое соединение с базой данных по завершении. Насколько мне известно, в коде приложения есть только одно место, где используются потоки: один блок использует модуль Ruby Timeout, но он не обращается к базе данных.

Следуя этому руководству https://devcenter.heroku.com/articles/concurrency-and-database-connections (на самом деле я не использую Heroku) Я установил размер пула соединений с базой данных равным 5 со следующим файлом конфигурации:

#config/initializers/database_connection.rb
Rails.application.config.after_initialize do
  ActiveRecord::Base.connection_pool.disconnect!

  ActiveSupport.on_load(:active_record) do
    config = ActiveRecord::Base.configurations[Rails.env] ||
                Rails.application.config.database_configuration[Rails.env]
    config['reaping_frequency'] = ENV['DB_REAP_FREQ'] || 10 # seconds
    config['pool']              = ENV['MAX_THREADS'] || 5 
    ActiveRecord::Base.establish_connection(config)
  end

конец

Сайт размещен с использованием Rails 4.0.0. Я читал, что на самом деле это может быть проблема Rails 4.0.0, и что это было исправлено в более поздних версиях, но я не уверен в этом. ConnectionTimeoutError на Heroku с Postgres

  1. Есть ли способ отслеживать количество активных подключений к базе данных в пуле подключений? Это значительно упростило бы отладку.
  2. Является ли использование модуля Timeout в коде приложения Rails причиной этой проблемы?
  3. Вероятно, это проблема Rails 4.0.0, а не проблема с моим приложением?

Приложение rails работает в производственной среде. Я могу предоставить больше информации о моей конфигурации Puma, NGINX, если это необходимо.


person user3868925    schedule 23.07.2014    source источник
comment
Я тоже вижу массу таких в приложении 4.1, чего я никогда не видел в 3.x, поэтому я думаю, что проблема на самом деле не решена.   -  person riffraff    schedule 26.09.2014
comment
Кто-нибудь нашел решение для этого? Я тоже это вижу. У меня есть подозрение, что это связано с драгоценным камнем airbrake и/или с использованием current_user в application_controller.rb. Кто-нибудь еще имеет эту ошибку, используя гем airbrake или используя current_user в application_controller.rb?   -  person Catfish    schedule 12.01.2015
comment
Переключив свой сервер разработки на webrick, я не вижу этой ошибки. Я думаю, что виновата пума.   -  person Catfish    schedule 13.01.2016


Ответы (2)


Тот факт, что отказоустойчивый ответ пытается выделить соединение с базой данных, может быть дымящимся пистолетом. Это может помочь вам описать, что происходит в отказоустойчивом ответе. Предположительно отказоустойчивый ответ был запущен, когда исходный запрос вызвал исключение. Подпрограмма rails show_exception, которая вызывает отказоустойчивый ответ, вызывается после того, как ConnectionManager вызывает clear_active_connections! для текущего запроса (который завершился ошибкой с исключением), а это означает, что rails не будет автоматически освобождать соединения с базой данных после того, как отказоустойчивый ответ завершится ошибкой. Это означает, что отказоустойчивый обработчик ответов отвечает за очистку своих собственных соединений с базой данных. Я не уверен, что это хорошая практика, когда обработчик отказоустойчивых ответов пытается подключиться к базе данных, но если это желаемое поведение, вам, возможно, придется вызвать clear_active_connections! явно в конце вашего отказоустойчивого обработчика (в блоке обеспечения).

Я исследовал аналогичную проблему в своем собственном приложении и обнаружил, что это полезное руководство по работе соединений: https://bibwild.wordpress.com/2014/07/17/activerecord-concurrency-in-rails4-avoid-leaked-connections/. Хотя приведенный здесь код может нуждаться в некоторых корректировках, в нем есть хорошее описание того, как определить, когда вы создаете неявное соединение с базой данных.

person ashanbrown    schedule 22.11.2014

Я не думаю, что это проблема рельсов 4.0.0.

Итак, как упоминалось в документации по модулю таймаута ruby, создать новую ветку. Я думаю, что есть шанс, что он может породить длинный поток, который будет поддерживать соединение с базой данных в реальном времени. Для проверки запущенных потоков вы можете использовать метод Thread.list. Также имейте в виду, что размер вашего пула должен быть >= чем потоки puma умножают работников puma.

person mpospelov    schedule 02.11.2014