web-dev-qa-db-fra.com

Erreur de dépôt Rails + Postgres: d'autres utilisateurs ont accès à la base de données.

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.

Modifier

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?

79
fjuan

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.

75
encoded

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.

29
Mr. Rene

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.

16
Jamon Holmgren

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

9
Matt Scilipoti

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
5
Chris Aitchison

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
5
Amol Udage

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.

5
Frank Heikens

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.

3
Joshua D. Drake

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'
1
Dan

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/ )

1
Manuel Meurer

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

0
Mutuma

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é!

0
ravip0711

Après avoir redémarré le serveur ou l'ordinateur, veuillez réessayer.

Cela pourrait être la solution simple.

0
hobbydev