Rails + Postgres放置错误:其他用户正在访问数据库


90

我有一个运行在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>

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

有什么方法可以终止postgres DB上的会话?

谢谢。

编辑

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

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


确保您没有与数据库的连接,否则它将不会删除它。在这里查看更多有关此内容
Nesha Zoric '18

Answers:


81

如果您终止了正在运行的应用程序的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
我必须将sudo添加到xargs并更改数据库名称,但是它可以工作。TY
lzap 2011年

1
对我来说一样...更改为“ sudo xargs kill”,并将硬编码的db_name更改为“ my-development-database-name”
Kevin Dewalt 2013年

6
task "db:drop" => :kill_postgres_connections我认为应该删除此行,从我的角度来看,这有扩展系统任务行为的危险。
msa.im 2013年

无需对数据库名称进行硬编码,只需使用以下命令:db_name = Rails.configuration.database_configuration[Rails.env]['database']
tala

39

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

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


结果中的哪个数字代表PID?我看到3个未标记的列,其编号类似于PID。
BradGreens

1
@BradGreens第二栏(我正在使用Mac Terminal)
s2t2

ps未找到任何内容,但仍然在db:drop上显示错误。
JosephK

17

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

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

警告:这将杀死postgres用户打开的所有正在运行的进程,因此请确保您首先要执行此操作。


11
在我的系统中,我sudo kill -9 `ps -u postgres -o pid=` 改为使用PID头,因此不会打印PID头,因此不会将ps字符串参数传递给kill,因此不会引发错误。无论如何都很棒的提示。
2013年

1
我不断提高和降低投票率,导致收视率接近零。似乎是一个有争议的“快速修复”。让我记录一下,我确实警告过危险。:)
Jamon Holmgren

3
如果您使用的是Ubuntu,请使用此命令再次启动postgresql:sudo service postgresql start
Frikster,

9

当我们从上面使用“ kill process”方法时,db:drop失败(如果:kill_postgres_connections是前提条件)。我相信这是因为rake命令使用的连接被杀死了。相反,我们使用sql命令删除连接。这是db:drop的先决条件,避免了通过相当复杂的命令杀死进程的风险,并且它可以在任何OS上运行(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,包括参考


8

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

您是否曾经阅读过该生产警告?只是好奇:P
Vinicius Brasil

6

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

停止Rails服务器和控制台。

然后跑

 rake db:drop

5

完成后,让您的应用程序关闭连接。PostgreSQL不会保持连接打开,而是保持连接的应用程序。


1
我可以使用phppgadmin的界面删除数据库,但不能使用rake任务删除数据库。如何使用rake任务复制phppgadmin的drop?
2010年

抱歉,不能为您服务,我没有耙的经验。但是,该错误表明另一个用户仍在使用数据库。这就是为什么您无法删除数据库,不能通过rake而不是PhpPgAdmin来删除数据库,这是不可能的。在手册中,DROP DATABASE:在您或任何其他人连接到目标数据库时无法执行。
Frank Heikens 2010年

3

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


如何强制Rails删除数据库?我应该使用postgres SQL命令定义自己的rake操作吗?
2010年

2

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

gem 'pgreset'

除了您的gem之外,什么也不会做-连接不存在(ps grep搜索等),但是Rails认为确实可以。非常感谢!!
6

1

您可以简单地修补执行删除操作的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/


1

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

这是我解决的方法

首先,注销到PGAdmin Client 上与数据库服务器的所有连接(如果有)。

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

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

就这样。

我希望这有帮助


1

这为我工作(第6条): rake db:drop:_unsafe

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


0

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


0

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


0

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

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


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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.