ruby-on-rails - proyecto - rails new myapp postgresql
Error de descarte de Rails+Postgres: otros usuarios están accediendo a la base de datos (12)
Tengo una aplicación de rieles sobre Postgres.
Tengo dos servidores: uno para probar y el otro para producción.
Muy a menudo necesito clonar el DB 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 abierta una "sesión")
¿Hay alguna forma de que pueda finalizar las sesiones en la base de datos Postgres?
Gracias.
Editar
Puedo eliminar la base de datos usando la interfaz de phppgadmin, pero no con la tarea de rake.
¿Cómo puedo replicar la caída de phppgadmin con una tarea de rake?
Aquí hay una forma rápida de eliminar todas las conexiones a su base de datos postgres.
sudo kill -9 `ps -u postgres -o pid`
Advertencia: esto matará todos los procesos en ejecución que el usuario de postgres
haya abierto, así que asegúrese de hacer esto primero.
Cuando usamos el método "matar procesos" desde arriba, el db: drop estaba fallando (si: kill_postgres_connections era un requisito previo). Creo que fue porque la conexión que ese comando de rake estaba usando estaba siendo asesinada. En cambio, estamos usando un comando sql para soltar la conexión. Esto funciona como un prerrequisito 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 prerrequisito para db: drop. Incluye una advertencia que grita después de actualizar los rieles, lo que indica que este parche ya no es necesario.
ver: https://gist.github.com/4455341 , referencias incluidas
Deje que su aplicación cierre la conexión cuando esté lista. PostgreSQL no mantiene las conexiones abiertas, es la aplicación que mantiene la conexión.
Es probable que Rails se conecte a la base de datos para soltarlo, pero cuando inicia sesión a través de phppgadmin, está iniciando sesión a través de la plantilla1 o la base de datos postgres, por lo que no se verá afectado.
Escribí una gema llamada pgreset que matará automáticamente las conexiones a la base de datos en cuestión cuando ejecute rake db: drop (o db: reset, etc.). Todo lo que tienes que hacer es agregarlo a tu Gemfile y este problema debería desaparecer. En el momento de escribir estas líneas, funciona con Rails 4 en adelante y ha sido probado en Postgres 9.x. El código fuente está disponible en github para cualquier persona interesada.
gem ''pgreset''
Si matas las conexiones postgresql en ejecución para tu aplicación, puedes ejecutar db: drop it fine. Entonces, ¿cómo matar esas conexiones? Uso la siguiente tarea de 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
Eliminar las conexiones de debajo de los rieles a veces hará que estalle la próxima vez que intentes cargar una página, pero volver a cargarla restablece la conexión.
Solo asegúrese de que haya salido de la consola de rieles en cualquier ventana de terminal abierta y haya salido del servidor de rieles ... este es uno de los errores más comunes cometidos por personas
Tuve un error similar al decir que 1 usuario estaba usando la base de datos, ¡me di cuenta de que era YO! Apagué el servidor de mis raíles y luego hice el comando rake: drop y ¡funcionó!
Una manera más fácil y más actualizada es: 1. Usar ps -ef | grep postgres
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.
Uso la siguiente tarea de rake para anular el método 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
Usted puede simplemente monopatchear el código de ActiveRecord que realiza la caída.
Para 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
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/ )
Verifique si la consola de sus raíles o el servidor se está ejecutando en otra pestaña y luego
detener el servidor y la consola de los rieles.
entonces corre
rake db:drop