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

时间:2010-03-03 08:37:46

标签: ruby-on-rails postgresql

我在Postgres上运行了一个rails应用程序。

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

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

我通过Vlad跑的命令是:

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上的会话吗?

谢谢。

修改

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

如何使用rake任务复制phppgadmin的drop?

17 个答案:

答案 0 :(得分:76)

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

下次尝试加载页面时,从导轨下面杀掉连接有时会导致barf barf,但重新加载它会重新建立连接。

答案 1 :(得分:32)

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

注意:可能存在相同的PID。杀一个人会杀死所有人。

答案 2 :(得分:16)

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

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

警告:这会终止postgres用户已打开的所有正在运行的进程,因此请确保首先执行此操作。

答案 3 :(得分:9)

当我们使用上面的“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任务,它从database.yml读取数据库名称并运行改进的(IMHO)命令。它还添加了db:kill_postgres_connections作为db:drop的先决条件。它包含一个警告,在您升级rails后会大喊,表示可能不再需要此补丁。

请参阅:https://gist.github.com/4455341,包含参考资料

答案 4 :(得分: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

答案 5 :(得分:5)

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

答案 6 :(得分:5)

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

停止rails服务器和控制台。

然后运行

 rake db:drop

答案 7 :(得分:3)

Rails很可能连接到数据库以丢弃它,但是当您通过phppgadmin登录时,它通过template1或postgres数据库登录,因此您不会受到它的影响。

答案 8 :(得分:2)

步骤 1

获取所有与 ps -ef | grep postgres 的 postgres 连接的列表

列表将如下所示:

  502   560   553   0 Thu08am ??         0:00.69 postgres: checkpointer process             
  502   565   553   0 Thu08am ??         0:00.06 postgres: bgworker: logical replication launcher
  502 45605   553   0  2:23am ??         0:00.01 postgres: st myapp_development [local] idle 

步骤 2

使用 sudo kill -9 <pid> 停止您想要的任何连接,其中 pid 是第二列中的值。就我而言,我想用 pid 45605 停止最后一行,所以我使用:

sudo kill -9 45605

答案 9 :(得分:1)

我编写了一个名为pgreset的gem,它会在你运行rake db:drop(或db:reset等)时自动终止与数据库的连接。您所要做的就是将它添加到您的Gemfile中,这个问题应该消失。在撰写本文时,它适用于Rails 4及更高版本,并已在Postgres 9.x上进行过测试。任何感兴趣的人都可以github获取源代码。

gem 'pgreset'

答案 10 :(得分:1)

在生产环境中使用Rails 5.2应用程序和PostgreSQL数据库时,我遇到了同样的问题。

这是我的解决方法

首先,注销与PGAdmin客户端上的数据库服务器的所有连接。

从终端使用数据库停止每个会话。

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

启动PostgreSQL服务器,因为上面的kill操作停止了PostgreSQL服务器。

sudo systemctl start postgresql

在生产环境中拖放数据库,并附加生产参数。

rails db:drop RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1

仅此而已。

我希望这会有所帮助

答案 11 :(得分:1)

这对我有用(导轨6): rake db:drop:_unsafe

我认为我们的代码库中有一些东西可以在rake任务尝试删除它之前启动db连接。

答案 12 :(得分:1)

您可以简单地对执行删除的ActiveRecord代码进行monkeypatch。

对于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/

答案 13 :(得分:0)

我有一个类似的错误说1个用户正在使用数据库,我意识到这是我!我关闭了我的rails服务器,然后执行了rake:drop命令,它运行了!

答案 14 :(得分:0)

只需确保您已在任何打开的终端窗口退出rails控制台并退出rails服务器......这是人们最常犯的错误之一

答案 15 :(得分:0)

重新启动服务器或计算机后,请重试。

这可能是简单的解决方案。

答案 16 :(得分:0)

解决方案

Bash脚本

ENV=development

# restart postgresql
brew services restart postgresql

# get name of the db from rails app
RAILS_CONSOLE_COMMAND="bundle exec rails c -e $ENV"
DB_NAME=$(echo 'ActiveRecord::Base.connection_config[:database]' | $RAILS_CONSOLE_COMMAND | tail -2 | tr -d '\"')

# delete all connections to $DB_NAME
for pid in $(ps -ef | grep $DB_NAME | awk {'print$2'})
do
   kill -9 $pid
done

# drop db
DISABLE_DATABASE_ENVIRONMENT_CHECK=1 RAILS_ENV=$ENV bundle exec rails db:drop:_unsafe