Mam aplikację railsową działającą na Postgres.
Mam dwa serwery: jeden do testowania, a drugi do produkcji.
Bardzo często muszę sklonować produkcyjną bazę danych na serwerze testowym.
Polecenie uruchamiane przez Vlada to:
rake RAILS_ENV='test_server' db:drop db:create
Problem polega na tym, że pojawia się następujący błąd:
ActiveRecord::StatementInvalid: PGError: ERROR: database <database_name> is being accessed by other users DROP DATABASE IF EXISTS <database_name>
Dzieje się tak, jeśli ktoś ostatnio uzyskał dostęp do aplikacji przez Internet (postgres utrzymuje otwartą „sesję”)
Czy jest jakiś sposób, żebym mógł zakończyć sesje w bazie danych postgres?
Dziękuję Ci.
Edytować
Mogę usunąć bazę danych za pomocą interfejsu phppgadmin, ale nie za pomocą zadania rake.
Jak mogę replikować drop phppgadmin za pomocą zadania rake?
ruby-on-rails
postgresql
fjuan
źródło
źródło
Odpowiedzi:
Jeśli zabijesz działające połączenia postgresql dla twojej aplikacji, możesz następnie uruchomić db: drop dobrze. Jak więc zabić te połączenia? Używam następującego zadania rake:
# 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
Zabijanie połączeń spod szyn czasami powoduje zerwanie połączenia przy następnej próbie załadowania strony, ale ponowne jej załadowanie przywraca połączenie.
źródło
task "db:drop" => :kill_postgres_connections
Myślę, że ten wiersz powinien zostać usunięty, z mojego punktu widzenia grozi to rozszerzeniem zachowania zadania systemowego.db_name = Rails.configuration.database_configuration[Rails.env]['database']
Prostszy i bardziej aktualny sposób to: 1. Użyj,
ps -ef | grep postgres
aby znaleźć połączenie # 2.sudo kill -9 "# of the connection
Uwaga: może istnieć identyczny PID. Zabicie jednego zabija wszystkich.
źródło
Oto szybki sposób na zabicie wszystkich połączeń z bazą danych postgres.
sudo kill -9 `ps -u postgres -o pid`
Ostrzeżenie: spowoduje to zabicie wszystkich uruchomionych procesów, które
postgres
użytkownik otworzył, więc upewnij się, że chcesz to zrobić najpierw.źródło
sudo kill -9 `ps -u postgres -o pid=`
zamiast tego, więc nagłówek PID nie zostanie wydrukowanyps
, więc argument łańcuchowy nie jest przekazywany dokill
, więc błąd nie zostanie zgłoszony. Świetna wskazówka w każdym przypadku.sudo service postgresql start
Kiedy użyliśmy powyższej metody „zabij procesy”, procedura db: drop nie powiodła się (jeśli warunek wstępny: kill_postgres_connections). Wydaje mi się, że to dlatego, że połączenie, którego używała ta komenda grabieży, zostało zabite. Zamiast tego używamy polecenia sql, aby porzucić połączenie. Działa to jako warunek wstępny dla db: drop, pozwala uniknąć ryzyka zabicia procesów za pomocą dość złożonej komendy i powinno działać na każdym systemie operacyjnym (dla Gentoo wymagana jest inna składnia
kill
).cmd = %(psql -c "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE procpid <> pg_backend_pid();" -d '#{db_name}')
Oto zadanie rake, które odczytuje nazwę bazy danych z database.yml i uruchamia ulepszoną komendę (IMHO). Dodaje również db: kill_postgres_connections jako warunek wstępny do db: drop. Zawiera ostrzeżenie, które krzyczy po aktualizacji szyn, wskazując, że ta poprawka może nie być już potrzebna.
patrz: https://gist.github.com/4455341 , w tym odniesienia
źródło
Używam następującego zadania rake, aby zastąpić
drop_database
metodę 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
źródło
Sprawdź, czy twoja konsola lub serwer rails działa na innej karcie, a następnie
zatrzymaj serwer railsowy i konsolę.
następnie uruchomić
rake db:drop
źródło
Pozwól aplikacji zamknąć połączenie po zakończeniu. PostgreSQL nie utrzymuje otwartych połączeń, to aplikacja utrzymuje połączenie.
źródło
Railsy prawdopodobnie łączą się z bazą danych, aby ją porzucić, ale kiedy logujesz się przez phppgadmin, loguje się przez bazę danych template1 lub postgres, więc nie ma to na ciebie wpływu.
źródło
Napisałem klejnot o nazwie pgreset , który automatycznie zabija połączenia z daną bazą danych po uruchomieniu rake db: drop (lub db: reset itp.). Wszystko, co musisz zrobić, to dodać go do pliku Gemfile, a ten problem powinien zniknąć. W chwili pisania tego tekstu działa z Railsami 4 i nowszymi oraz został przetestowany na Postgres 9.x. Kod źródłowy jest dostępny na github dla wszystkich zainteresowanych.
źródło
To zadziałało dla mnie (szyny 6):
rake db:drop:_unsafe
Myślę, że mieliśmy coś w naszej bazie kodu, co zainicjowało połączenie bazy danych, zanim zadanie rake'a próbowało je porzucić.
źródło
Możesz po prostu wpisać monkeypatch kod ActiveRecord, który wykonuje upuszczanie.
Dla 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
Dla 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
(z: http://www.krautcomputing.com/blog/2014/01/10/how-to-drop-your-postgres-database-with-rails-4/ )
źródło
Miałem ten sam problem podczas pracy z aplikacją Rails 5.2 i bazą danych PostgreSQL w środowisku produkcyjnym.
Oto jak to rozwiązałem :
Najpierw wyloguj się z każdego połączenia z serwerem bazy danych na kliencie PGAdmin, jeśli takie istnieje.
Zatrzymaj każdą sesję przy użyciu bazy danych z terminala.
sudo kill -9 `ps -u postgres -o pid=`
Uruchom serwer PostgreSQL, ponieważ powyższa operacja kill zatrzymała serwer PostgreSQL.
sudo systemctl start postgresql
Usuń bazę danych w środowisku produkcyjnym, dołączając argumenty produkcyjne.
rails db:drop RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1
To wszystko.
mam nadzieję, że to pomoże
źródło
Tylko upewnij się, że opuściłeś konsolę rails w dowolnym otwartym oknie terminala i opuściłeś serwer rails ... to jeden z najczęstszych błędów popełnianych przez ludzi
źródło
Miałem podobny błąd, że 1 użytkownik korzystał z bazy danych, zdałem sobie sprawę, że to JA! Wyłączyłem serwer rails, a następnie wykonałem polecenie rake: drop i zadziałało!
źródło
Po ponownym uruchomieniu serwera lub komputera spróbuj ponownie.
To mogłoby być proste rozwiązanie.
źródło
Rozwiązanie
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
źródło