Rails + Postgres drop error: ผู้ใช้รายอื่นกำลังเข้าถึงฐานข้อมูล


92

ฉันมีแอปพลิเคชั่นรางที่ทำงานบน Postgres

ฉันมีเซิร์ฟเวอร์สองเครื่อง: เซิร์ฟเวอร์หนึ่งสำหรับการทดสอบและอีกเซิร์ฟเวอร์หนึ่งสำหรับการผลิต

บ่อยครั้งที่ฉันต้องโคลนฐานข้อมูลการผลิตบนเซิร์ฟเวอร์ทดสอบ

คำสั่งที่ฉันเรียกใช้ผ่าน 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 แต่ไม่สามารถใช้กับงานคราดได้

ฉันจะทำซ้ำการดรอป phppgadmin ด้วยงานคราดได้อย่างไร


ตรวจสอบให้แน่ใจว่าคุณไม่มีการเชื่อมต่อกับฐานข้อมูลมิฉะนั้นจะไม่ทิ้ง ตรวจสอบข้อมูลเพิ่มเติมเกี่ยวกับที่นี่
Nesha Zoric

คำตอบ:


82

หากคุณฆ่าการเชื่อมต่อ 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
ฉันต้องเพิ่ม sudo ใน xargs และเปลี่ยนชื่อฐานข้อมูล แต่มันใช้งานได้ TY
lzap

1
เหมือนกันสำหรับฉัน ... เปลี่ยนเป็น "sudo xargs kill" และฮาร์ดโค้ด db_name เป็น "my-development-database-name"
Kevin Dewalt

7
task "db:drop" => :kill_postgres_connectionsฉันคิดว่าบรรทัดนี้ควรถูกลบออกไปมันอันตรายที่จะขยายพฤติกรรมของงานระบบจากมุมมองของฉัน
Sergey Makridenkov

แทนที่จะใช้ฮาร์ดโค้ดชื่อฐานข้อมูลของคุณให้ใช้สิ่งต่อไปนี้:db_name = Rails.configuration.database_configuration[Rails.env]['database']
tala

41

วิธีที่ง่ายและอัปเดตมากขึ้นคือ 1. ใช้ps -ef | grep postgresเพื่อค้นหาการเชื่อมต่อ # 2sudo kill -9 "# of the connection

หมายเหตุ: อาจมี PID เหมือนกัน ฆ่าคนเดียวฆ่าทั้งหมด


ตัวเลขใดในผลลัพธ์ที่แสดงถึง PID ฉันเห็นคอลัมน์ที่ไม่มีป้ายกำกับ 3 คอลัมน์พร้อมตัวเลขที่ดูเหมือน PID
BradGreens

3
คอลัมน์ที่สองของ @BradGreens (ฉันใช้ Mac Terminal)
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

1
ฉันได้รับการโหวตเพิ่มและลดคะแนนอยู่เรื่อย ๆ ส่งผลให้คะแนนเกือบเป็นศูนย์ ดูเหมือนจะเป็น "การแก้ไขด่วน" ที่ขัดแย้งกัน ให้ฉันระบุสำหรับบันทึกว่าฉันได้เตือนว่ามันเป็นอันตราย :)
Jamon Holmgren

3
ใช้สิ่งนี้เพื่อเริ่ม postgresql อีกครั้งหากคุณใช้ Ubuntu:sudo service postgresql start
Frikster

9

เมื่อเราใช้เมธอด "kill กระบวนการ" จากด้านบน db: drop ล้มเหลว (ถ้า: kill_postgres_connections เป็นข้อกำหนดเบื้องต้น) ฉันเชื่อว่าเป็นเพราะการเชื่อมต่อที่ใช้คำสั่งคราดนั้นกำลังถูกฆ่า แต่เราใช้คำสั่ง 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}')

นี่คืองานคราดที่อ่านชื่อฐานข้อมูลจาก database.yml และรันคำสั่ง (IMHO) ที่ปรับปรุงแล้ว นอกจากนี้ยังเพิ่ม db: kill_postgres_connections เป็นสิ่งที่จำเป็นต้องมีให้กับ db: drop มันมีคำเตือนที่ตะโกนหลังจากที่คุณอัพเกรดรางซึ่งบ่งบอกว่าอาจไม่จำเป็นต้องใช้แพตช์นี้อีกต่อไป

ดู: https://gist.github.com/4455341รวมข้อมูลอ้างอิง


9

ฉันใช้งานคราดต่อไปนี้เพื่อแทนที่drop_databaseเมธอด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

คุณเคยอ่านคำเตือนการผลิตหรือไม่? อยากรู้อยากเห็น: P
Vinicius Brasil

6

โปรดตรวจสอบว่าคอนโซลรางหรือเซิร์ฟเวอร์ของคุณกำลังทำงานในแท็บอื่นหรือไม่

หยุดเซิร์ฟเวอร์รางและคอนโซล

จากนั้นเรียกใช้

 rake db:drop

5

ให้แอปพลิเคชันของคุณปิดการเชื่อมต่อเมื่อเสร็จสิ้น PostgreSQL ไม่เปิดการเชื่อมต่อเนื่องจากเป็นแอปพลิเคชันที่รักษาการเชื่อมต่อ


1
ฉันสามารถลบฐานข้อมูลโดยใช้อินเทอร์เฟซของ phppgadmin แต่ไม่สามารถใช้กับงานคราดได้ ฉันจะทำซ้ำการดรอป phppgadmin ด้วยงานคราดได้อย่างไร
fjuan

ขออภัยไม่สามารถช่วยคุณได้ฉันไม่มีประสบการณ์เกี่ยวกับคราด แต่ข้อผิดพลาดระบุว่าผู้ใช้รายอื่นยังคงใช้ฐานข้อมูลอยู่ นั่นเป็นเหตุผลที่คุณไม่สามารถลบฐานข้อมูลไม่ใช่โดยการคราดโดย PhpPgAdmin เป็นไปไม่ได้ จากคู่มือ DROP DATABASE: ไม่สามารถดำเนินการได้ในขณะที่คุณหรือใครก็ตามเชื่อมต่อกับฐานข้อมูลเป้าหมาย
Frank Heikens

3

Rails มีแนวโน้มที่จะเชื่อมต่อกับฐานข้อมูลเพื่อดร็อป แต่เมื่อคุณเข้าสู่ระบบผ่าน phppgadmin จะมีการเข้าสู่ระบบผ่านฐานข้อมูล template1 หรือ postgres ดังนั้นคุณจะไม่ได้รับผลกระทบจากมัน


ฉันจะบังคับให้รางวางฐานข้อมูลได้อย่างไร ฉันควรกำหนดการกระทำคราดของตัวเองโดยใช้คำสั่ง postgres SQL หรือไม่
fjuan

2

ฉันเขียนอัญมณีชื่อpgresetซึ่งจะฆ่าการเชื่อมต่อกับฐานข้อมูลที่เป็นปัญหาโดยอัตโนมัติเมื่อคุณเรียกใช้ rake db: drop (หรือ db: reset ฯลฯ ) สิ่งที่คุณต้องทำคือเพิ่มลงใน Gemfile ของคุณปัญหานี้จะหายไป ในขณะที่เขียนนี้ใช้งานได้กับ Rails 4 ขึ้นไปและได้รับการทดสอบบน Postgres 9.x. ซอร์สโค้ดมีอยู่ในgithubสำหรับทุกคนที่สนใจ

gem 'pgreset'

ไม่มีอะไรนอกจากอัญมณีของคุณจะทำมัน - ไม่มีการเชื่อมต่อ (การค้นหา ps grep ฯลฯ ) แต่รางคิดว่ามันทำได้ ขอบคุณมาก!!
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=`

เริ่มต้นเซิร์ฟเวอร์ PostgreSQL เนื่องจากการดำเนินการ kill ด้านบนหยุดเซิร์ฟเวอร์ PostgreSQL

sudo systemctl start postgresql

วางฐานข้อมูลในสภาพแวดล้อมการผลิตต่อท้ายอาร์กิวเมนต์การผลิต

rails db:drop RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1

นั่นคือทั้งหมด

ฉันหวังว่านี่จะช่วยได้


1

สิ่งนี้ได้ผลสำหรับฉัน (ราง 6): rake db:drop:_unsafe

ฉันคิดว่าเรามีบางอย่างใน codebase ของเราที่เริ่มต้นการเชื่อมต่อ db ก่อนที่งานคราดจะพยายามวาง


0

ตรวจสอบให้แน่ใจว่าคุณได้ออกจากคอนโซลรางบนหน้าต่างเทอร์มินัลที่เปิดอยู่และออกจากเซิร์ฟเวอร์ราง ... นี่เป็นหนึ่งในความผิดพลาดที่เกิดขึ้นบ่อยที่สุดโดยผู้คน


0

ฉันมีข้อผิดพลาดที่คล้ายกันโดยบอกว่าผู้ใช้ 1 คนกำลังใช้ฐานข้อมูลฉันรู้ว่ามันคือฉัน! ฉันปิดเซิร์ฟเวอร์รางของฉันจากนั้นทำคำสั่ง rake: drop และใช้งานได้!



0

วิธีการแก้

สคริปต์ทุบตี

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.