Ошибка сброса 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 DB?



спасибо.



Edit



Я могу удалить базу данных с помощью интерфейса phppgadmin, но не с помощью задачи rake.



Как я могу повторить падение phppgadmin с помощью задачи rake?

564   12  

12 ответов:

Если вы убиваете запущенные соединения 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 }' \
  | xargs kill
EOF
  puts `#{sh}`
end

task "db:drop" => :kill_postgres_connections

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

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

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

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

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

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

когда мы использовали метод "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}')

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

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

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

Я использую следующую задачу грабли, чтобы переопределить рельсы 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

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

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

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

 rake db:drop

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

вы можете просто monkeypatch код ActiveRecord, который делает падение.

Для Рельсов 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

Для Рельсов 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/)

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

gem 'pgreset'

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

У меня была аналогичная ошибка, говоря, что 1 пользователь использует базу данных, я понял, что это я! Я закрыл свой сервер rails, а затем сделал команду rake:drop, и это сработало!

Comments

    Ничего не найдено.