Erreur de chute Rails + Postgres: access à la firebase database par d’autres utilisateurs

J’ai une application de rails sur Postgres.

J’ai deux serveurs: un pour les tests et l’autre pour la production.

Très souvent, je dois cloner la firebase database de production sur le serveur de test.

La commande que je lance via Vlad est la suivante:

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

Le problème que j’ai est que je reçois l’erreur suivante:

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

Cela se produit si quelqu’un a accédé à l’application via le Web récemment (postgres conserve une “session” ouverte)

Est-il possible de terminer les sessions sur la firebase database postgres?

Je vous remercie.

modifier

Je peux supprimer la firebase database en utilisant l’interface de phppgadmin mais pas avec la tâche de rake.

Comment puis-je répliquer la chute de phppgadmin avec une tâche de rake?

Si vous tuez les connexions postgresql en cours d’exécution pour votre application, vous pouvez alors exécuter db: drop très bien. Alors, comment tuer ces connexions? J’utilise la tâche suivante:

 # lib/tasks/kill_postgres_connections.rake task :kill_postgres_connections => :environment do db_name = "#{File.basename(Rails.root)}_#{Rails.env}" sh = <  :kill_postgres_connections 

Tuer les connexions à partir de sous-rails la fera parfois barber la prochaine fois que vous essayez de charger une page, mais le recharger à nouveau rétablit la connexion.

La manière la plus simple et la plus à jour est de: 1. Utiliser ps -ef | grep postgres ps -ef | grep postgres pour trouver la connexion # 2. sudo kill -9 "# of the connection

Remarque: il peut y avoir des PID identiques. Tuer un tue tout.

Voici un moyen rapide de supprimer toutes les connexions à votre firebase database postgres.

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

Attention: cela va tuer tous les processus en cours que l’utilisateur postgres a ouverts, alors assurez-vous de vouloir le faire en premier.

Lorsque nous avons utilisé la méthode “kill process” ci-dessus, le db: drop échouait (si: kill_postgres_connections était pré-requirejs). Je crois que c’était parce que la connexion utilisée par cette commande était en train d’être tuée. Au lieu de cela, nous utilisons une commande sql pour supprimer la connexion. Cela fonctionne comme une condition préalable pour db: drop, évite le risque de tuer des processus via une commande plutôt complexe, et il devrait fonctionner sur n’importe quel système d’exploitation (gentoo nécessitant une syntaxe différente pour kill ).

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

Voici une tâche rake qui lit le nom de la firebase database à partir de database.yml et exécute une commande améliorée (IMHO). Il ajoute également db: kill_postgres_connections comme condition préalable à db: drop. Il inclut un avertissement qui indique après la mise à niveau des rails, indiquant que ce correctif n’est peut-être plus nécessaire.

voir: https://gist.github.com/4455341 , références incluses

Laissez votre application fermer la connexion lorsque c’est fait. PostgreSQL ne garde pas les connexions ouvertes, c’est l’application qui conserve la connexion.

J’utilise la tâche rake suivante pour remplacer la méthode 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 

Veuillez vérifier si votre console de rails ou votre serveur fonctionne dans un autre onglet, puis

arrêtez le serveur de rails et la console.

puis courir

  rake db:drop 

Rails se connecte probablement à la firebase database pour le déposer, mais lorsque vous vous connectez via phppgadmin, il se connecte via la firebase database template1 ou postgres, vous n’êtes donc pas concerné.

Vous pouvez simplement saisir le code ActiveRecord qui effectue le saut.

Pour 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 

Pour 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 

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

J’ai écrit un joyau appelé pgreset qui va automatiquement tuer les connexions à la firebase database en question lorsque vous exécutez rake db: drop (ou db: reset, etc.). Tout ce que vous avez à faire est de l’append à votre Gemfile et ce problème devrait disparaître. Au moment d’écrire ces lignes, il fonctionne avec Rails 4 et supérieur et a été testé sur Postgres 9.x. Le code source est disponible sur github pour toute personne intéressée.

 gem 'pgreset' 

Assurez-vous simplement que vous avez quitté la console de rails sur n’importe quelle fenêtre de terminal ouverte et que vous avez quitté le serveur de rails … c’est l’une des erreurs les plus courantes commises par des personnes.

J’ai eu une erreur similaire en disant que 1 utilisateur utilisait la firebase database, j’ai réalisé que c’était ME! J’ai arrêté mon serveur de rails et j’ai ensuite fait le rake: drop command et ça a fonctionné!