Ошибка удаления Rails + Postgres: к базе данных обращаются другие пользователи - PullRequest
81 голосов
/ 03 марта 2010

У меня есть приложение 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 с помощью рейка?

Ответы [ 13 ]

76 голосов
/ 22 апреля 2011

Если вы убьете работающие соединения postgresql для своего приложения, вы можете запустить db: drop просто отлично. Так как же убить эти связи? Я использую следующие грабли:

# 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

Уничтожение подключений из-под направляющих иногда приводит к тому, что они прерываются при следующей загрузке страницы, но при повторной загрузке происходит повторное установление соединения.

32 голосов
/ 02 октября 2016

Более простым и обновленным способом является: 1. Используйте ps -ef | grep postgres, чтобы найти соединение # 2. sudo kill -9 "# of the connection

Примечание. Может быть идентичный PID. Убийство одного убивает всех.

16 голосов
/ 19 июня 2012

Вот быстрый способ уничтожить все соединения с вашей базой данных postgres.

sudo kill -9 `ps -u postgres -o pid` 

Предупреждение: это уничтожит все запущенные процессы, открытые пользователем postgres, поэтому сначала убедитесь, что вы хотите это сделать.

9 голосов
/ 05 января 2013

Когда мы использовали метод «kill process», описанный выше, 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}')

Вот задача rake, которая считывает имя базы данных из database.yml и запускает улучшенную (IMHO) команду. Он также добавляет db: kill_postgres_connections в качестве предварительного условия для db: drop. Он содержит предупреждение, которое выкрикивает после обновления рельсы, указывая на то, что этот патч больше не нужен.

см .: https://gist.github.com/4455341, ссылки включены

6 голосов
/ 31 марта 2013

Я использую следующую задачу 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
5 голосов
/ 06 ноября 2015

Проверьте, запущена ли ваша консоль rails или сервер на другой вкладке, а затем

остановка сервера и консоли rails.

затем запустите

 rake db:drop
5 голосов
/ 03 марта 2010

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

3 голосов
/ 04 марта 2010

Rails, вероятно, подключается к базе данных, чтобы удалить ее, но когда вы входите через phppgadmin, он входит через базу данных template1 или postgres, таким образом, это не влияет на вас.

1 голос
/ 30 сентября 2016

Я написал гем под названием pgreset , который автоматически уничтожает соединения с рассматриваемой базой данных при запуске rake db: drop (или db: reset и т. Д.). Все, что вам нужно сделать, это добавить его в свой Gemfile, и эта проблема должна исчезнуть. На момент написания этой статьи он работал с Rails 4 и выше и был протестирован на Postgres 9.x. Исходный код доступен на github для всех, кто заинтересован.

gem 'pgreset'
1 голос
/ 10 января 2014

Вы можете просто обезопасить код 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

(от: http://www.krautcomputing.com/blog/2014/01/10/how-to-drop-your-postgres-database-with-rails-4/)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...