Rails + Postgres drop error:数据库正在被其他用户访问

我有一个运行在Postgres上的Rails应用程序。

我有两台服务器:一台用于testing,另一台用于生产。

我经常需要在testing服务器上克隆生产数据库。

我是通过弗拉德runnig命令是:

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> 

如果有人通过networking最近访问了应用程序,这会发生(postgres保持“会话”打开)

有什么办法可以终止postgres数据库上的会话吗?

谢谢。

编辑

我可以使用phppgadmin的界面删除数据库,但不能使用rake任务。

我怎样才能用rake任务复制phppgadmin的drop?

如果你为你的应用程序终止正在运行的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 

从轨下杀死连接有时会导致它在下次尝试加载页面时被禁止,但是重新加载它会重新build立连接。

更简单更新的方式是:1.使用ps -ef | grep postgres ps -ef | grep postgresfind连接# sudo kill -9 "# of the connection

注意:可能有相同的PID。 杀死所有人。

这是一个快速杀死所有连接到你的postgres数据库的方法。

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

警告:这将会postgres用户打开的任何正在运行的进程,所以确保你想要这样做。

当我们使用上面的“kill processes”方法时,db:drop失败(如果:kill_postgres_connections是先决条件)。 我相信这是因为耙指令所使用的连接正在被杀死。 相反,我们正在使用一个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的先决条件。 它包含一个警告,在你升级rails之后大叫,说明这个补丁可能不再需要了。

请参阅: https : //gist.github.com/4455341 ,包括参考

让应用程序在完成时closures连接。 PostgreSQL不保持连接打开,这是应用程序保持连接。

我使用下面的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 

请检查您的导轨控制台或服务器是否在另一个选项卡中运行

停止rails服务器和控制台。

然后运行

  rake db:drop 

Rails可能会连接到数据库来删除它,但是当通过phppgadminlogin时,它将通过template1或postgres数据库login,因此您不会受到影响。

您可以简单地monkeypatch删除的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/ )

我写了一个名为pgreset的gem,当你运行rake db:drop(或db:reset等)的时候,它会自动终止连接到有问题的数据库。 所有你需要做的就是把它添加到你的Gemfile,这个问题应该消失。 在写这篇文章的时候,它和Rails 4一起工作,并且已经在Postgres 9.x上testing过了。 任何感兴趣的人都可以在github上find源代码。

 gem 'pgreset' 

只要确保你已经在任何打开的terminal窗口退出轨道控制台并退出轨道服务器…这是人们最常犯的错误之一

我有一个类似的错误说1用户正在使用数据库,我意识到这是我! 我closures了我的Rails服务器,然后做了rake:drop命令,它工作!