Ошибка Rails + Postgres: доступ к базе данных осуществляется другими пользователями
У меня есть приложение rails, работающее над Postgres.
У меня есть два сервера: один для тестирования, а другой для производства.
Очень часто мне нужно клонировать производственную БД на тестовом сервере.
Команда, которую я запускаю через Влада:
rake RAILS_ENV='test_server' db:drop db:create
Проблема, с которой я сталкиваюсь, заключается в том, что я получаю следующую ошибку:
ActiveRecord::StatementInvalid: PGError: ERROR: database <database_name> is being accessed by other users DROP DATABASE IF EXISTS <database_name>
Это происходит, если кто-то недавно обратился к приложению через веб-сайт (postgres сохраняет открытую сессию)
Есть ли способ, которым я могу завершить сеансы в базе данных postgres?
Спасибо.
Изменить
Я могу удалить базу данных с помощью интерфейса phppgadmin, но не с помощью команды rake.
Как я могу реплицировать падение phppgadmin с помощью команды rake?
Ответы
Ответ 1
Если вы убьете запущенные соединения postgresql для своего приложения, вы можете запустить db: drop просто отлично. Итак, как убить эти соединения? Я использую следующую команду rake:
# lib/tasks/kill_postgres_connections.rake
task :kill_postgres_connections => :environment do
db_name = "#{File.basename(Rails.root)}_#{Rails.env}"
sh = <<EOF
ps xa \
| grep postgres: \
| grep #{db_name} \
| grep -v grep \
| awk '{print $1}' \
| xargs kill
EOF
puts `#{sh}`
end
task "db:drop" => :kill_postgres_connections
Убивание соединений из-под рельсов иногда приводит к тому, что в следующий раз при попытке загрузить страницу перезагружается, но перезагрузка снова заново устанавливает соединение.
Ответ 2
Проще и более обновленный способ:
1. Используйте ps -ef | grep postgres
, чтобы найти соединение #
2. sudo kill -9 "# of the connection
Примечание. Может быть идентичный PID. Убийство одного убивает всех.
Ответ 3
Здесь можно быстро удалить все подключения к базе данных postgres.
sudo kill -9 `ps -u postgres -o pid`
Предупреждение: это убьет любые запущенные процессы, которые пользователь postgres
открыл, поэтому убедитесь, что вы хотите сделать это в первую очередь.
Ответ 4
Когда мы использовали метод "kill processes" сверху, произошел сбой db: drop (если: kill_postgres_connections было необходимым условием). Я считаю, что это связано с тем, что была убита связь, которую использовала команда rake. Вместо этого мы используем команду sql, чтобы удалить соединение. Это работает как предварительное условие для db: drop, избегает риска убийства процессов с помощью довольно сложной команды и должно работать на любой ОС (gentoo требует различного синтаксиса для kill
).
cmd = %(psql -c "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE procpid <> pg_backend_pid();" -d '#{db_name}')
Вот грабельная задача, которая считывает имя базы данных из базы данных .yml и выполняет улучшенную (IMHO) команду. Он также добавляет db: kill_postgres_connections как обязательное условие для db: drop. Он включает предупреждение, которое кричит после обновления рельсов, что указывает на то, что этот патч больше не нужен.
см. https://gist.github.com/4455341, ссылки включены
Ответ 5
Позвольте вашему приложению закрыть соединение, когда оно будет выполнено. PostgreSQL не поддерживает открытые подключения, это приложение поддерживает соединение.
Ответ 6
Я использую следующую команду rake для переопределения метода Rails drop_database
.
lib/database.rake
require 'active_record/connection_adapters/postgresql_adapter'
module ActiveRecord
module ConnectionAdapters
class PostgreSQLAdapter < AbstractAdapter
def drop_database(name)
raise "Nah, I won't drop the production database" if Rails.env.production?
execute <<-SQL
UPDATE pg_catalog.pg_database
SET datallowconn=false WHERE datname='#{name}'
SQL
execute <<-SQL
SELECT pg_terminate_backend(pg_stat_activity.pid)
FROM pg_stat_activity
WHERE pg_stat_activity.datname = '#{name}';
SQL
execute "DROP DATABASE IF EXISTS #{quote_table_name(name)}"
end
end
end
end
Ответ 7
Пожалуйста, проверьте, что консоль рельсов или сервер работает на другой вкладке, а затем
остановить сервер и консоль рельсов.
затем запустите
rake db:drop
Ответ 8
Rails, скорее всего, подключается к базе данных, чтобы отбросить его, но когда вы входите в систему через phppgadmin, он регистрируется через базу данных template1 или postgres, поэтому на вас это не влияет.
Ответ 9
Вы можете просто обезвредить код ActiveRecord, который выполняет сброс.
Для Rails 3.x:
# lib/tasks/databases.rake
def drop_database(config)
raise 'Only for Postgres...' unless config['adapter'] == 'postgresql'
Rake::Task['environment'].invoke
ActiveRecord::Base.connection.select_all "select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where datname='#{config['database']}' AND state='idle';"
ActiveRecord::Base.establish_connection config.merge('database' => 'postgres', 'schema_search_path' => 'public')
ActiveRecord::Base.connection.drop_database config['database']
end
Для Rails 4.x:
# config/initializers/postgresql_database_tasks.rb
module ActiveRecord
module Tasks
class PostgreSQLDatabaseTasks
def drop
establish_master_connection
connection.select_all "select pg_terminate_backend(pg_stat_activity.pid) from pg_stat_activity where datname='#{configuration['database']}' AND state='idle';"
connection.drop_database configuration['database']
end
end
end
end
(from: http://www.krautcomputing.com/blog/2014/01/10/how-to-drop-your-postgres-database-with-rails-4/)
Ответ 10
Я написал драгоценный камень под названием pgreset, который автоматически уничтожит соединения с соответствующей базой данных при запуске rake db: drop (или db: reset и т.д.). Все, что вам нужно сделать, это добавить его в свой Gemfile, и эта проблема должна исчезнуть. На момент написания этой статьи он работает с Rails 4 и выше и был протестирован на Postgres 9.x. Исходный код доступен на github для всех, кто интересуется.
gem 'pgreset'
Ответ 11
Просто убедитесь, что вы вышли из консоли rails в любое открытое окно терминала и вышли из сервера rails... это одна из самых распространенных ошибок, сделанных людьми
Ответ 12
У меня была аналогичная ошибка: 1 пользователь использовал базу данных, я понял, что это ME! Я отключил сервер рельсов, а затем сделал команду rake: drop, и она сработала!
Ответ 13
После перезапуска сервера или компьютера попробуйте еще раз.
Это может быть простое решение.