J'ai une application Rails s'exécutant sur Postgres.
J'ai deux serveurs: un pour les tests et l'autre pour la production.
Très souvent, j'ai besoin de cloner la base de données de production sur le serveur de test.
La commande que je lance via Vlad est:
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 <database_name> is being accessed by other users DROP DATABASE IF EXISTS <database_name>
Cela se produit si une personne a récemment accédé à l'application via Internet (Postgres conserve une "session" ouverte)
Existe-t-il un moyen de terminer les sessions sur la base de données postgres?
Je vous remercie.
Je peux supprimer la base de données en utilisant l'interface de phppgadmin mais pas avec la tâche rake.
Comment puis-je répliquer la chute de phppgadmin avec une tâche rake?
Si vous supprimez les connexions postgresql en cours d'exécution pour votre application, vous pouvez alors exécuter db: drop. Alors, comment tuer ces connexions? J'utilise la tâche de rake suivante:
# 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
Si vous supprimez les connexions sous Rails, il risque parfois de provoquer un échec la prochaine fois que vous essayez de charger une page, mais son rechargement rétablit la connexion.
Une manière plus facile et plus à jour est: 1. Utilisez ps -ef | grep postgres
pour trouver le numéro de connexion. 2. Sudo kill -9 "# of the connection
Remarque: Il peut y avoir un PID identique. Tuer un tue tous.
Voici un moyen rapide de supprimer toutes les connexions à votre base de données postgres.
Sudo kill -9 `ps -u postgres -o pid`
Avertissement: cela supprimera tous les processus en cours que l'utilisateur postgres
a ouverts. Assurez-vous donc de le faire en premier.
Lorsque nous avons utilisé la méthode "kill processus" ci-dessus, la base de données: drop échouait (si: kill_postgres_connections était une condition préalable requise). Je crois que c’est parce que la connexion utilisée par cette commande de ratissage était en train d’être supprimé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 devrait fonctionner sur n’importe quel système d’exploitation (gentoo a requis 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 base de données à 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 crie après la mise à niveau de Rails, indiquant que ce correctif n'est peut-être plus nécessaire.
voir: https://Gist.github.com/4455341 , références incluses
J'utilise la tâche de rake suivante pour remplacer la méthode Rails drop_database
.
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 ou votre serveur Rails est exécuté dans un autre onglet, puis
arrêtez le serveur Rails et la console.
puis courir
rake db:drop
Laissez votre application fermer la connexion une fois l'opération terminée. PostgreSQL ne garde pas les connexions ouvertes, c'est l'application qui garde la connexion.
Il est probable que Rails se connecte à la base de données pour la supprimer, mais lorsque vous vous connectez via phppgadmin, il se connecte via la base de données template1 ou postgres. Par conséquent, cela ne vous concerne pas.
J'ai écrit une gemme appelée pgreset qui va automatiquement tuer les connexions à la base de données en question lorsque vous exécutez rake db: drop (ou db: reset, etc.) Tout ce que vous avez à faire est de l’ajouter à votre Gemfile et ce problème devrait disparaître. Au moment d'écrire ces lignes, cela fonctionne avec Rails 4 et plus et a été testé sur Postgres 9.x. Le code source est disponible sur github pour toute personne intéressée.
gem 'pgreset'
Vous pouvez simplement monkeypatch le code ActiveRecord qui effectue le largage.
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/ )
Assurez-vous simplement que vous avez quitté la console Rails sur n'importe quelle fenêtre de terminal ouverte et sur le serveur Rails ... c'est l'une des erreurs les plus courantes commises par des personnes
J'ai eu une erreur similaire en disant qu'un utilisateur utilisait la base de données, j'ai réalisé que c'était moi! J'ai arrêté mon serveur Rails puis j'ai exécuté la commande rake: drop et tout a fonctionné!
Après avoir redémarré le serveur ou l'ordinateur, veuillez réessayer.
Cela pourrait être la solution simple.