Rails + Postgres drop error: database sedang diakses oleh pengguna lain

91

Saya memiliki aplikasi rel yang berjalan di atas Postgres.

Saya memiliki dua server: satu untuk pengujian dan yang lainnya untuk produksi.

Sangat sering saya perlu mengkloning DB produksi di server pengujian.

Perintah yang saya jalankan melalui Vlad adalah:

rake RAILS_ENV='test_server' db:drop db:create

Masalah yang saya alami adalah saya menerima kesalahan berikut ini:

ActiveRecord::StatementInvalid: PGError: ERROR: database <database_name> is being accessed by other users DROP DATABASE IF EXISTS <database_name>

Ini terjadi jika seseorang baru-baru ini mengakses aplikasi melalui web (postgres membuat "sesi" tetap terbuka)

Apakah ada cara agar saya dapat menghentikan sesi di DB postgres?

Terima kasih.

Edit

Saya dapat menghapus database menggunakan antarmuka phppgadmin tetapi tidak dengan tugas rake.

Bagaimana cara mereplikasi drop phppgadmin dengan rake task?

fjuan
sumber
Pastikan Anda tidak memiliki koneksi ke database atau database tidak akan menjatuhkannya. Lihat lebih lanjut tentang ini di sini .
Nesha Zoric

Jawaban:

81

Jika Anda mematikan koneksi postgresql yang sedang berjalan untuk aplikasi Anda, Anda dapat menjalankan db: drop dengan baik. Jadi bagaimana cara mematikan koneksi tersebut? Saya menggunakan tugas menyapu berikut:

# 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

Mematikan koneksi dari bawah rel terkadang akan menyebabkannya muntah saat Anda mencoba memuat halaman lagi, tetapi memuatnya kembali akan membuat koneksi kembali.

dikodekan
sumber
2
Saya harus menambahkan sudo ke xargs dan mengubah nama database, tetapi berhasil. TY
lzap
1
Sama untuk saya ... diubah menjadi "sudo xargs kill" dan db_name hard-code menjadi "my-development-database-name"
Kevin Dewalt
6
task "db:drop" => :kill_postgres_connectionsSaya pikir baris ini harus dihapus, berbahaya untuk memperluas perilaku tugas sistem, dari pandangan saya.
msa.im
Daripada melakukan hardcode nama database Anda, cukup gunakan berikut ini:db_name = Rails.configuration.database_configuration[Rails.env]['database']
tala
41

Cara yang lebih mudah dan lebih update adalah: 1. Gunakan ps -ef | grep postgresuntuk mencari koneksi # 2.sudo kill -9 "# of the connection

Catatan: Mungkin ada PID yang identik. Membunuh satu membunuh semua.

Tuan Rene
sumber
Angka manakah yang mewakili PID? Saya melihat 3 kolom tidak berlabel dengan angka yang terlihat seperti PID.
BradGreens
3
@BradGreens kolom kedua (Saya menggunakan Terminal Mac)
s2t2
Tidak ada yang ditemukan dengan ps, tapi masih mendapatkan kesalahan pada db: drop.
JosephK
17

Berikut cara cepat untuk mematikan semua koneksi ke database postgres Anda.

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

Peringatan: ini akan menghentikan semua proses yang sedang berjalan yang postgresdibuka pengguna, jadi pastikan Anda ingin melakukan ini terlebih dahulu.

Jamon Holmgren
sumber
11
Dalam sistem saya, saya menggunakan sudo kill -9 `ps -u postgres -o pid=` sebagai gantinya, jadi header PID tidak akan dicetak oleh ps, jadi argumen string tidak diteruskan kill, jadi kesalahan tidak akan dimunculkan. Tip bagus dalam hal apapun.
membagikan
1
Saya terus mendapatkan suara positif dan suara negatif, sehingga peringkat saya hampir nol. Tampaknya menjadi "perbaikan cepat" yang kontroversial. Izinkan saya menyatakan sebagai catatan bahwa saya memang memberikan peringatan bahwa itu berbahaya. :)
Jamon Holmgren
3
Gunakan ini untuk memulai postgresql lagi jika Anda menggunakan Ubuntu:sudo service postgresql start
Frikster
9

Ketika kami menggunakan metode "kill proses" dari atas, db: drop gagal (jika: kill_postgres_connections merupakan prasyarat). Saya percaya itu karena koneksi yang digunakan oleh perintah rake telah dimatikan. Sebagai gantinya, kami menggunakan perintah sql untuk memutuskan koneksi. Ini berfungsi sebagai prasyarat untuk db: drop, menghindari risiko mematikan proses melalui perintah yang agak rumit, dan harus bekerja pada OS apa pun (gentoo memerlukan sintaks yang berbeda kill).

cmd = %(psql -c "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE procpid <> pg_backend_pid();" -d '#{db_name}')

Berikut adalah tugas menyapu yang membaca nama database dari database.yml dan menjalankan perintah yang ditingkatkan (IMHO). Itu juga menambahkan db: kill_postgres_connections sebagai prasyarat untuk db: drop. Ini termasuk peringatan yang berteriak setelah Anda meningkatkan rel, menunjukkan bahwa tambalan ini mungkin tidak lagi diperlukan.

lihat: https://gist.github.com/4455341 , referensi disertakan

Matt Scilipoti
sumber
8

Saya menggunakan tugas rake berikut untuk mengganti drop_databasemetode Rails .

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
Chris Aitchison
sumber
Apakah Anda pernah membaca peringatan produksi itu? Hanya penasaran: P
Vinicius Brasil
6

Silakan periksa apakah konsol atau server rel Anda berjalan di tab lain dan kemudian

hentikan server rel dan konsol.

lalu lari

 rake db:drop
Amol Udage
sumber
5

Biarkan aplikasi Anda menutup koneksi setelah selesai. PostgreSQL tidak menjaga koneksi tetap terbuka, itu adalah aplikasi yang menjaga koneksi.

Frank Heikens
sumber
1
Saya dapat menghapus database menggunakan antarmuka phppgadmin tetapi tidak dengan tugas rake. Bagaimana cara mereplikasi drop phppgadmin dengan rake task?
fjuan
Maaf, tidak dapat membantu Anda di sana, saya tidak memiliki pengalaman dengan rake. Namun, kesalahan menunjukkan pengguna lain masih menggunakan database. Itulah mengapa Anda tidak dapat menghapus database, tidak dengan rake bukan oleh PhpPgAdmin, tidak mungkin. Dari manual, DROP DATABASE: itu tidak dapat dijalankan saat Anda atau orang lain terhubung ke database target.
Frank Heikens
3

Rails kemungkinan akan terhubung ke database untuk menjatuhkannya tetapi ketika Anda masuk melalui phppgadmin, ia masuk melalui database template1 atau postgres, sehingga Anda tidak terpengaruh olehnya.

Joshua D. Drake
sumber
Bagaimana saya bisa memaksa rel untuk menjatuhkan database? Haruskah saya mendefinisikan aksi rake saya sendiri menggunakan perintah SQL postgres?
fjuan
2

Saya menulis permata bernama pgreset yang secara otomatis akan mematikan koneksi ke database yang dimaksud ketika Anda menjalankan rake db: drop (atau db: reset, dll). Yang harus Anda lakukan adalah menambahkannya ke Gemfile Anda dan masalah ini akan hilang. Pada saat penulisan ini bekerja dengan Rails 4 dan lebih tinggi dan telah diuji pada Postgres 9.x. Kode sumber tersedia di github untuk siapa saja yang tertarik.

gem 'pgreset'
Dan
sumber
Tidak ada selain permata Anda yang akan melakukannya - koneksi tidak ada (ps grep mencari dll), tetapi rails berpikir demikian. Terimakasih banyak!!
JosephK
2

Ini berhasil untuk saya (rel 6): rake db:drop:_unsafe

Saya pikir kami memiliki sesuatu di basis kode kami yang memulai koneksi db sebelum tugas rake mencoba menjatuhkannya.

cyrilchampier
sumber
1

Anda cukup mencocokkan kode ActiveRecord yang melakukan penurunan.

Untuk 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

Untuk 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

(dari: http://www.krautcomputing.com/blog/2014/01/10/how-to-drop-your-postgres-database-with-rails-4/ )

Manuel Meurer
sumber
1

Saya mengalami masalah yang sama saat bekerja dengan aplikasi Rails 5.2 dan database PostgreSQL dalam produksi.

Inilah cara saya menyelesaikannya :

Pertama, logout setiap koneksi ke server database di Klien PGAdmin jika ada.

Hentikan setiap sesi menggunakan database dari terminal.

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

Mulai server PostgreSQL, karena operasi kill di atas menghentikan server PostgreSQL.

sudo systemctl start postgresql

Jatuhkan database di lingkungan produksi dengan menambahkan argumen produksi.

rails db:drop RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1

Itu saja.

saya harap ini membantu

Janji Preston
sumber
0

Pastikan bahwa Anda telah keluar dari konsol rel di jendela terminal yang terbuka dan keluar dari server rel ... ini adalah salah satu kesalahan paling umum yang dilakukan oleh orang-orang

Mutuma
sumber
0

Saya mengalami kesalahan serupa yang mengatakan 1 pengguna menggunakan database, saya menyadari itu adalah SAYA! Saya mematikan server rel saya dan kemudian melakukan perintah rake: drop dan berhasil!

ravip0711.dll
sumber
0

Setelah server atau komputer dimulai ulang, coba lagi.

Ini bisa menjadi solusi sederhana.

hobbydev
sumber
0

Larutan

Skrip 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
Bodnarchuk dengan mudah
sumber