Tengo una aplicación de rieles que se ejecuta en Postgres.
Tengo dos servidores: uno para pruebas y otro para producción.
Muy a menudo necesito clonar la base de datos de producción en el servidor de prueba.
El comando que estoy ejecutando a través de Vlad es:
rake RAILS_ENV='test_server' db:drop db:create
El problema que tengo es que recibo el siguiente error:
ActiveRecord::StatementInvalid: PGError: ERROR: database <database_name> is being accessed by other users DROP DATABASE IF EXISTS <database_name>
Esto sucede si alguien ha accedido a la aplicación a través de la web recientemente (postgres mantiene una "sesión" abierta)
¿Hay alguna forma de que pueda terminar las sesiones en la base de datos de postgres?
Gracias.
Editar
Puedo eliminar la base de datos usando la interfaz de phppgadmin pero no con la tarea rake.
¿Cómo puedo replicar la caída de phppgadmin con una tarea de rake?
ruby-on-rails
postgresql
fjuan
fuente
fuente
Respuestas:
Si cancela las conexiones postgresql en ejecución para su aplicación, puede ejecutar db: drop sin problemas. Entonces, ¿cómo eliminar esas conexiones? Utilizo la siguiente tarea de rastrillo:
# 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
Eliminar las conexiones de debajo de los rieles a veces hará que la próxima vez que intente cargar una página se eche a vomitar, pero volver a cargarla restablecerá la conexión.
fuente
task "db:drop" => :kill_postgres_connections
Creo que esta línea debería eliminarse, es peligroso extender el comportamiento de la tarea del sistema, desde mi punto de vista.db_name = Rails.configuration.database_configuration[Rails.env]['database']
La forma más fácil y actualizada es: 1. Use
ps -ef | grep postgres
para encontrar la conexión # 2.sudo kill -9 "# of the connection
Nota: Puede haber un PID idéntico. Matar a uno mata a todos.
fuente
Aquí hay una forma rápida de eliminar todas las conexiones a su base de datos de postgres.
sudo kill -9 `ps -u postgres -o pid`
Advertencia: esto matará cualquier proceso en ejecución que el
postgres
usuario haya abierto, así que asegúrese de querer hacer esto primero.fuente
sudo kill -9 `ps -u postgres -o pid=`
en su lugar, por lo que no se imprimirá un encabezado PIDps
, por lo que no se le pasa un argumento de cadenakill
, por lo que no se generará un error. Buen consejo en cualquier caso.sudo service postgresql start
Cuando usamos el método de "matar procesos" de arriba, el db: drop fallaba (si: kill_postgres_connections era un requisito previo). Creo que fue porque la conexión que usaba el comando rake estaba siendo eliminada. En cambio, estamos usando un comando sql para eliminar la conexión. Esto funciona como un requisito previo para db: drop, evita el riesgo de matar procesos a través de un comando bastante complejo y debería funcionar en cualquier sistema operativo (gentoo requiere una sintaxis diferente para
kill
).cmd = %(psql -c "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE procpid <> pg_backend_pid();" -d '#{db_name}')
Aquí hay una tarea de rake que lee el nombre de la base de datos de database.yml y ejecuta un comando mejorado (en mi humilde opinión). También agrega db: kill_postgres_connections como requisito previo a db: drop. Incluye una advertencia que grita después de actualizar rieles, lo que indica que es posible que este parche ya no sea necesario.
ver: https://gist.github.com/4455341 , referencias incluidas
fuente
Utilizo la siguiente tarea de rake para anular el
drop_database
método 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
fuente
Compruebe si su consola o servidor de rails se está ejecutando en otra pestaña y luego
Detenga el servidor de rieles y la consola.
entonces corre
rake db:drop
fuente
Deje que su aplicación cierre la conexión cuando esté lista. PostgreSQL no mantiene abiertas las conexiones, es la aplicación la que mantiene la conexión.
fuente
Es probable que Rails se conecte a la base de datos para eliminarlo, pero cuando inicia sesión a través de phppgadmin, está iniciando sesión a través de la base de datos template1 o postgres, por lo que no se ve afectado por ella.
fuente
Esto funcionó para mí (rieles 6):
rake db:drop:_unsafe
Creo que teníamos algo en nuestro código base que inició una conexión de base de datos antes de que la tarea de rastrillo intentara eliminarlo.
fuente
Escribí una gema llamada pgreset que eliminará automáticamente las conexiones a la base de datos en cuestión cuando ejecute rake db: drop (o db: reset, etc.). Todo lo que tiene que hacer es agregarlo a su Gemfile y este problema debería desaparecer. En el momento de escribir este artículo, funciona con Rails 4 y versiones posteriores y se ha probado en Postgres 9.x. El código fuente está disponible en github para cualquier persona interesada.
fuente
Simplemente puede parchear el código ActiveRecord que hace la caída.
Para rieles 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
Para 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/ )
fuente
Tuve este mismo problema cuando trabajaba con una aplicación Rails 5.2 y una base de datos PostgreSQL en producción.
Así es como lo resolví :
Primero, cierre la sesión de todas las conexiones al servidor de la base de datos en el Cliente PGAdmin, si corresponde.
Detenga cada sesión usando la base de datos del terminal.
sudo kill -9 `ps -u postgres -o pid=`
Inicie el servidor PostgreSQL, ya que la operación de eliminación anterior detuvo el servidor PostgreSQL.
sudo systemctl start postgresql
Coloque la base de datos en el entorno de producción agregando los argumentos de producción.
rails db:drop RAILS_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1
Eso es todo.
espero que esto ayude
fuente
Solo asegúrese de haber salido de la consola de rieles en cualquier ventana de terminal abierta y salido del servidor de rieles ... este es uno de los errores más comunes que cometen las personas
fuente
Tuve un error similar que decía que 1 usuario estaba usando la base de datos, ¡me di cuenta de que era YO! Apagué mi servidor de rieles y luego hice el comando rake: drop y ¡funcionó!
fuente
Después de reiniciar el servidor o la computadora, vuelva a intentarlo.
Podría ser la solución más sencilla.
fuente
Solución
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
fuente