我在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?
答案 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)
获取所有与 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
使用 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