Rails + Postgresドロップエラー:他のユーザーがデータベースにアクセスしています


90

Postgres上でRailsアプリケーションを実行しています。

2つのサーバーがあります。1つはテスト用、もう1つは本番用です。

テストサーバーに運用データベースのクローンを作成する必要があることがよくあります。

私が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タスクでは削除できません。

phppgadminのドロップをrakeタスクでどのように複製できますか?


データベースへの接続がないこと、またはデータベースがドロップされないことを確認してください。詳しくはこちらをご覧ください
Nesha Zoric

回答:


81

アプリケーションで実行中の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 $1}' \
  | xargs kill
EOF
  puts `#{sh}`
end

task "db:drop" => :kill_postgres_connections

レールの下から接続を強制終了すると、次にページをロードしようとしたときにバーフが発生することがありますが、再度ロードすると、接続が再確立されます。


2
xargsにsudoを追加してデータベース名を変更する必要がありましたが、機能します。TY
lzap 2011

1
私も同じです... "sudo xargs kill"に変更され、db_nameが "my-development-database-name"にハードコードされました
Kevin Dewalt

6
task "db:drop" => :kill_postgres_connections私の考えでは、この行は削除する必要があると思います。システムタスクの動作を拡張することは危険です。
msa.im 2013

:むしろ打ちよりも、自分のデータベース名は、単に以下の使用db_name = Rails.configuration.database_configuration[Rails.env]['database']
ターラ

39

より簡単で更新された方法は次のとおりです。1 ps -ef | grep postgres.接続を見つけるために使用します#2。sudo kill -9 "# of the connection

注:同一のPIDが存在する場合があります。1人を殺すとすべてが殺されます。


結果のどの番号がPIDを表しますか?PIDのような番号の付いた3つのラベルのない列が表示されます。
BradGreens

1
@BradGreens 2列目(私はMacターミナルを使用しています)
s2t2 '19年

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ヘッダーはによって出力されないpsため、文字列引数はに渡されないkillため、エラーは発生しません。とにかく素晴らしいヒント。
2013

1
私は賛成票と反対票を取得し続け、その結果、評価はほぼゼロになりました。論争の的になっている「迅速な修正」のようです。私それが危険であるという警告を与えたという記録のために単に述べさせてください。:)
Jamon Holmgren 2013

3
あなたがUbuntuのにしている場合は、再度のPostgreSQLを開始するためにこれを使用しますsudo service postgresql start
Frikster

9

上記の「プロセスの強制終了」メソッドを使用すると、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}')

これは、database.ymlからデータベース名を読み取り、改良された(IMHO)コマンドを実行するrakeタスクです。また、db:dropの前提条件としてdb:kill_postgres_connectionsを追加します。Railsのアップグレード後に叫ぶ警告が含まれています。これは、このパッチが不要になったことを示しています。

参照:https : //gist.github.com/4455341、含まれる参照


8

Rails drop_databaseメソッドをオーバーライドするには、次のrakeタスクを使用します。

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タスクでは削除できません。phppgadminのドロップをrakeタスクでどのように複製できますか?
fjuan

すみません、あなたを助けられません。私はレーキの経験がありません。ただし、このエラーは、別のユーザーがまだデータベースを使用していることを示しています。これが、PhpPgAdminではなくレーキではなく、データベースを削除できない理由です。マニュアルから、DROP DATABASE:自分または他の誰かがターゲットデータベースに接続している間は実行できません。
フランクハイケンス

3

Railsはデータベースに接続してドロップする可能性がありますが、phppgadminを介してログインすると、template1またはpostgresデータベースを介してログインしているため、影響を受けません。


レールにデータベースを強制的にドロップさせるにはどうすればよいですか?postgres SQLコマンドを使用して独自のレイクアクションを定義する必要がありますか?
fjuan

2

rake db:drop(またはdb:resetなど)を実行すると、問題のデータベースへの接続を自動的に強制終了するpgresetと呼ばれるgemを書きました。あなたがしなければならないすべてはあなたのGemfileにそれを追加することであり、この問題はなくなるはずです。この記事の執筆時点では、Rails 4以降で動作し、Postgres 9.xでテストされています。興味のある方はソースコードをgithubから入手できます。

gem 'pgreset'

あなたのgem以外はそれを行いません-接続は存在しませんでしたが(ps grep searchなど)、railsはそれを考えました。どうもありがとう!!
JosephK

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クライアントのデータベースサーバーへのすべての接続をログアウトします。

端末からデータベースを使用するすべてのセッションを停止します。

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

上記のkill操作によりPostgreSQLサーバーが停止したため、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サーバーを終了したことを確認してください...これは、人が犯す最も一般的な間違いの1つです


0

1人のユーザーがデータベースを使用しているという私と同じようなエラーがありました。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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.