Rails + Postgres bırakma hatası: veritabanına diğer kullanıcılar erişiyor


92

Postgres üzerinden çalışan bir ray uygulamam var.

İki sunucum var: biri test, diğeri üretim için.

Çoğu zaman üretim DB'sini test sunucusunda klonlamam gerekir.

Vlad aracılığıyla çalıştırdığım komut:

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

Yaşadığım sorun şu hatayı almamdır:

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

Bu, birisi uygulamaya yakın zamanda web üzerinden erişmişse olur (postgres bir "oturum" açık tutar)

Postgres DB'de oturumları sonlandırmanın bir yolu var mı?

Teşekkür ederim.

Düzenle

Veritabanını phppgadmin arayüzünü kullanarak silebilirim, ancak rake göreviyle silebilirim.

Phppgadmin'in düşüşünü bir komisyon göreviyle nasıl kopyalayabilirim?


Veritabanına bağlantınız olmadığından emin olun, yoksa onu bırakmaz. Bununla ilgili daha fazlasını buradan kontrol edin .
Nesha Zoric

Yanıtlar:


82

Uygulamanız için çalışan postgresql bağlantılarını sonlandırırsanız, db: drop'u sorunsuz bir şekilde çalıştırabilirsiniz. Peki bu bağlantılar nasıl kesilir? Aşağıdaki komisyon görevini kullanıyorum:

# 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

Bağlantıları rayların altından kesmek bazen bir sonraki sayfa yüklemeyi denediğinizde tıkanmasına neden olur, ancak yeniden yüklemek bağlantıyı yeniden kurar.


2
Xargs'a sudo eklemek ve veritabanı adını değiştirmek zorunda kaldım ama işe yarıyor. TY
lzap

1
Benim için aynısı ... "sudo xargs kill" olarak değiştirildi ve sabit kodlu db_name "geliştirme-veritabanı-adım" olarak değiştirildi
Kevin Dewalt

7
task "db:drop" => :kill_postgres_connectionsBu satırın kaldırılması gerektiğini düşünüyorum, benim görüşüme göre sistem görevinin davranışını genişletmek tehlikelidir.
msa.im

Veritabanı adınızı sabit kodlamak yerine aşağıdakileri kullanın:db_name = Rails.configuration.database_configuration[Rails.env]['database']
tala

41

Daha kolay ve daha güncel bir yol: 1. ps -ef | grep postgres2 numaralı bağlantıyı bulmak için kullanın .sudo kill -9 "# of the connection

Not: Aynı PID olabilir. Birini öldürmek herkesi öldürür.


Sonuçtaki hangi sayı PID'yi temsil eder? PID'ye benzeyen sayılara sahip etiketlenmemiş 3 sütun görüyorum.
BradGreens

3
@BradGreens ikinci sütun (Mac Terminal kullanıyorum)
s2t2

Ps ile hiçbir şey bulunamadı, ancak yine de db: drop'da hata alınıyor.
JosephK

17

Postgres veritabanınıza yapılan tüm bağlantıları kesmenin hızlı bir yolu.

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

Uyarı: Bu, postgreskullanıcının açmış olduğu tüm çalışan işlemleri öldürecektir , bu nedenle önce bunu yapmak istediğinizden emin olun.


11
Benim sistemimde sudo kill -9 `ps -u postgres -o pid=` bunun yerine kullanıyorum, bu yüzden bir PID başlığı basılmayacak ps, bu yüzden bir string argümanı geçirilmeyecek kill, böylece bir hata oluşmayacak. Her durumda harika bir ipucu.
2013

1
Sürekli oy alıyorum ve olumsuz oy alıyorum, bu da sıfıra yakın bir puanla sonuçlanıyor. Tartışmalı bir "hızlı çözüm" gibi görünüyor. Kayıt için tehlikeli olduğuna dair bir uyarı yaptığımı belirtmeme izin verin. :)
Jamon Holmgren

3
Ubuntu'daysanız postgresql'i tekrar başlatmak için bunu kullanın:sudo service postgresql start
Frikster

9

Yukarıdaki "süreçleri öldür" yöntemini kullandığımızda, db: drop başarısız oluyordu (eğer: kill_postgres_connections önkoşuldu). Sanırım tırmık komutanının kullandığı bağlantı öldürülüyordu. Bunun yerine, bağlantıyı kesmek için bir sql komutu kullanıyoruz. Bu, db: drop için bir ön koşul olarak çalışır, oldukça karmaşık bir komutla süreçleri öldürme riskini ortadan kaldırır ve herhangi bir işletim sisteminde çalışmalıdır (gentoo için farklı sözdizimi gerekir kill).

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

Burada veritabanı adını database.yml dosyasından okuyan ve geliştirilmiş bir (IMHO) komutunu çalıştıran bir rake görevi verilmiştir. Ayrıca db: drop'a ön koşul olarak db: kill_postgres_connections ekler. Rayları yükselttikten sonra bağıran ve bu yamanın artık gerekli olmayabileceğini belirten bir uyarı içerir.

bkz: https://gist.github.com/4455341 , referanslar dahil


9

Rails drop_databaseyöntemini geçersiz kılmak için aşağıdaki komisyon görevini kullanıyorum .

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

Hiç bu üretim uyarısını okudunuz mu? Merak ediyorum: P
Vinicius Brasil

6

Lütfen ray konsolunuzun veya sunucunuzun başka bir sekmede çalışıp çalışmadığını kontrol edin ve ardından

raylar sunucusunu ve konsolu durdurun.

o zaman koş

 rake db:drop

5

Tamamlandığında uygulamanızın bağlantıyı kapatmasına izin verin. PostgreSQL bağlantıları açık tutmaz, bağlantıyı sağlayan uygulamadır.


1
Veritabanını phppgadmin arayüzünü kullanarak silebilirim ancak rake göreviyle silebilirim. Phppgadmin'in düşüşünü bir komisyon göreviyle nasıl kopyalayabilirim?
fjuan

Maalesef sana yardımcı olamam, tırmıkla ilgili deneyimim yok. Ancak hata, başka bir kullanıcının hala veritabanını kullandığını gösterir. Bu yüzden veritabanını PhpPgAdmin tarafından rake ile silemezsiniz, imkansızdır. Kılavuzdan, DROP DATABASE: siz veya başka biri hedef veritabanına bağlıyken yürütülemez.
Frank Heikens

3

Rails, veritabanını düşürmek için büyük olasılıkla veritabanına bağlanıyor, ancak phppgadmin aracılığıyla oturum açtığınızda, template1 veya postgres veritabanı aracılığıyla oturum açıyor, dolayısıyla bundan etkilenmiyorsunuz.


Rayları veritabanını bırakmaya nasıl zorlayabilirim? Postgres SQL komutlarını kullanarak kendi rake eylemimi tanımlamalı mıyım?
fjuan

3

Bu benim için çalıştı (raylar 6): rake db:drop:_unsafe

Sanırım kod tabanımızda komisyon görevi onu bırakmaya çalışmadan önce bir db bağlantısı başlatan bir şey vardı.


2

Rake db: drop (veya db: reset, vb.) Çalıştırdığınızda söz konusu veritabanına olan bağlantıları otomatik olarak kesecek pgreset adında bir mücevher yazdım . Tek yapmanız gereken onu Gemfile'ınıza eklemek ve bu sorun ortadan kalkacaktır. Bu yazının yazıldığı sırada Rails 4 ve üstü ile çalışıyor ve Postgres 9.x üzerinde test edildi. Kaynak kodu, ilgilenen herkes için github'da mevcuttur .

gem 'pgreset'

Cevheriniz dışında hiçbir şey bunu yapmazdı - bağlantı mevcut değildi (ps grep arama vb.), Ancak raylar öyle olduğunu düşündü. Çok teşekkürler!!
JosephK

1

Bırakmayı gerçekleştiren ActiveRecord kodunu basitçe maymun ekleyebilirsin.

Rails 3.x için:

# 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 için:

# 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

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


1

Üretimde bir Rails 5.2 uygulaması ve PostgreSQL veritabanı ile çalışırken aynı sorunu yaşadım.

İşte bunu nasıl çözdüm :

Öncelikle, varsa , PGAdmin İstemcisindeki veritabanı sunucusuna yapılan her bağlantıyı kapatın .

Terminaldeki veritabanını kullanarak her oturumu durdurun.

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

Yukarıdaki kill işlemi PostgreSQL sunucusunu durdurduğu için PostgreSQL sunucusunu başlatın.

sudo systemctl start postgresql

Üretim bağımsız değişkenlerini ekleyerek veritabanını üretim ortamına bırakın.

rails db:drop RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1

Bu kadar.

Umarım bu yardımcı olur


0

Herhangi bir açık terminal penceresinde ray konsolundan çıktığınızdan ve raylar sunucusundan çıktığınızdan emin olun ... bu, insanlar tarafından yapılan en yaygın hatalardan biridir.


0

Veritabanını 1 kullanıcının kullandığını söyleyen benzer bir hata yaşadım, bunun BENİM olduğunu anladım! Rails sunucumu kapattım ve ardından rake: drop komutunu yaptım ve işe yaradı!


0

Sunucuyu veya bilgisayarı yeniden başlattıktan sonra lütfen tekrar deneyin.

Basit bir çözüm olabilir.


0

Çözüm

Bash betiği

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.