Rails + Postgres 드롭 오류 : 다른 사용자가 데이터베이스에 액세스하고 있습니다.


91

Postgres를 통해 실행되는 레일 애플리케이션이 있습니다.

두 개의 서버가 있습니다. 하나는 테스트 용이고 다른 하나는 프로덕션 용입니다.

종종 테스트 서버에서 프로덕션 DB를 복제해야합니다.

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 작업으로는 삭제할 수 없습니다.

레이크 작업으로 phppgadmin의 드롭을 복제하려면 어떻게해야합니까?


데이터베이스에 연결되어 있지 않은지 확인하십시오. 그렇지 않으면 삭제되지 않습니다. 여기에서 자세한 내용을 확인 하십시오 .
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

1
변경 ... 나를 위해 같은 "sudo는 xargs를 죽일"와 "내 개발 데이터베이스 이름"에 DB_NAME 하드 코딩
케빈 DEWALT

6
task "db:drop" => :kill_postgres_connections이 줄을 제거해야한다고 생각합니다. 시스템 작업의 동작을 확장 할 위험이 있습니다.
msa.im

데이터베이스 이름을 하드 코딩하는 대신 다음을 사용하십시오.db_name = Rails.configuration.database_configuration[Rails.env]['database']
tala

41

더 쉽고 업데이트 된 방법은 다음과 같습니다. 1. ps -ef | grep postgres연결 # 2.을 찾는 데 사용 합니다.sudo kill -9 "# of the connection

참고 : 동일한 PID가있을 수 있습니다. 하나를 죽이면 모두 죽습니다.


결과에서 PID를 나타내는 숫자는 무엇입니까? PID처럼 보이는 숫자가있는 레이블이없는 3 개의 열이 있습니다.
BradGreens

3
@BradGreens 두 번째 열 (Mac 터미널을 사용하고 있습니다)
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 헤더가에 의해 인쇄되지 않으므로 ps문자열 인수가에 전달 kill되지 않으므로 오류가 발생하지 않습니다. 어쨌든 훌륭한 팁.
deivid 2013-08-03

1
나는 계속 찬성 및 반대 투표를 받아 거의 0에 가까운 등급을 얻었습니다. 논란의 여지가있는 "빠른 수정"인 것 같습니다. 내가하는 레코드 만 상태 나하자 했다 가 위험하다는 경고를 제공합니다. :)
Jamon Holmgren

3
Ubuntu를 사용하는 경우이를 사용하여 postgresql을 다시 시작합니다.sudo service postgresql start
Frikster

9

위의 "kill processes"방법을 사용했을 때 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) 명령을 실행하는 레이크 작업입니다. 또한 db : drop의 전제 조건으로 db : kill_postgres_connections를 추가합니다. 레일을 업그레이드 한 후에는이 패치가 더 이상 필요하지 않을 수 있음을 알리는 경고가 포함됩니다.

참조 : https://gist.github.com/4455341 , 참조 포함


8

다음 레이크 작업을 사용하여 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
비니 브라질

6

Rails 콘솔 또는 서버가 다른 탭에서 실행 중인지 확인한 다음

레일 서버와 콘솔을 중지하십시오.

그런 다음 실행

 rake db:drop

5

연결이 완료되면 애플리케이션이 연결을 종료하도록합니다. PostgreSQL은 연결을 유지하지 않고 연결을 유지하는 애플리케이션입니다.


1
phppgadmin의 인터페이스를 사용하여 데이터베이스를 삭제할 수 있지만 rake 작업으로는 삭제할 수 없습니다. 레이크 작업으로 phppgadmin의 드롭을 복제하려면 어떻게해야합니까?
fjuan

죄송합니다. 도와 드릴 수 없습니다. 레이크에 대한 경험이 없습니다. 그러나 오류는 다른 사용자가 여전히 데이터베이스를 사용하고 있음을 나타냅니다. 그렇기 때문에 PhpPgAdmin이 아닌 레이크로 데이터베이스를 삭제할 수 없으며 불가능합니다. 매뉴얼에서 DROP DATABASE : 사용자 또는 다른 사람이 대상 데이터베이스에 연결되어있는 동안에는 실행할 수 없습니다.
Frank Heikens

3

Rails는 데이터베이스에 연결하여 삭제할 가능성이 있지만 phppgadmin을 통해 로그인하면 template1 또는 postgres 데이터베이스를 통해 로그인하므로 영향을받지 않습니다.


레일이 데이터베이스를 삭제하도록하려면 어떻게해야합니까? postgres SQL 명령을 사용하여 내 레이크 액션을 정의해야합니까?
fjuan 2010 년

2

rake db : drop (또는 db : reset 등)을 실행할 때 문제의 데이터베이스에 대한 연결을 자동으로 종료 하는 pgreset 이라는 gem을 작성했습니다 . Gemfile에 추가하기 만하면이 문제는 사라집니다. 이 글을 쓰는 시점에서는 Rails 4 이상에서 작동하며 Postgres 9.x에서 테스트되었습니다. 소스 코드는 관심있는 사람이라면 누구나 github 에서 사용할 수 있습니다 .

gem 'pgreset'

보석 외에는 아무것도 할 수 없습니다-연결이 존재하지 않았지만 (ps grep 검색 등) Rails는 그렇게 생각했습니다. 고맙습니다!!
JosephK

2

이것은 나를 위해 일했습니다 (레일 6). rake db:drop:_unsafe

rake 작업이 연결을 끊기 전에 db 연결을 시작한 코드베이스에 무언가가 있다고 생각합니다.


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=`

위의 종료 작업이 PostgreSQL 서버를 중지 했으므로 PostgreSQL 서버를 시작합니다.

sudo systemctl start postgresql

프로덕션 인수를 추가하여 프로덕션 환경에서 데이터베이스를 삭제하십시오.

rails db:drop RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1

그게 다야.

이게 도움이 되길 바란다


0

열려있는 터미널 창에서 레일 콘솔을 종료하고 레일 서버를 종료했는지 확인하십시오. 이것은 사람들이 저지르는 가장 일반적인 실수 중 하나입니다.


0

한 명의 사용자가 데이터베이스를 사용하고 있다는 비슷한 오류가 발생했습니다. 레일스 서버를 종료 한 다음 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.