ruby on rails - Capistrano con PostgreSQL, error: otros usuarios acceden a la base de datos
ruby-on-rails (3)
Tengo una aplicación de Rails que usa PostgreSQL como un backend con un entorno cert que intenta imitar la producción, excepto que necesita tener el restablecimiento de la base de datos periódicamente para QA.
Cuando intento ejecutar db:reset
desde una tarea de Capistrano durante la implementación, aparece el error:
ERROR: database "database_name" is being accessed by other users
y la base de datos no se puede descartar como parte de la tarea de restablecimiento que da como resultado un error de implementación. ¿Hay alguna manera de restablecer las conexiones de la base de datos de Capistrano para poder eliminar la tabla con éxito? Podía funcionar el SQL a psql desde una tarea de Capistrano, pero me preguntaba si habría una mejor manera de hacerlo.
Con PostgreSQL puede emitir la siguiente declaración para devolver los pids de back-end de todas las conexiones abiertas, excepto esta:
SELECT pid FROM pg_stat_activity where pid <> pg_backend_pid();
Luego puede emitir una solicitud de terminación para cada uno de esos backends con
SELECT pg_terminate_backend($1);
Vinculación de los pids devueltos desde la primera declaración a cada ejecutivo pg_terminate_backend.
Si las otras conexiones no utilizan el mismo usuario que usted, tendrá que conectarse como superusuario para emitir con éxito los extremos.
- Funciones de señalización del administrador
- Funciones de monitoreo de estadísticas
- pg_stat_activity ver documentos
ACTUALIZACIÓN: Incorporación de comentarios y expresión como tarea de Capistrano:
desc "Force disconnect of open backends and drop database"
task :force_close_and_drop_db do
dbname = ''your_database_name''
run "psql -U postgres",
:data => <<-"PSQL"
REVOKE CONNECT ON DATABASE #{dbname} FROM public;
ALTER DATABASE #{dbname} CONNECTION LIMIT 0;
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE pid <> pg_backend_pid()
AND datname=''#{dbname}'';
DROP DATABASE #{dbname};
PSQL
end
He combinado la respuesta de dbenhur con esta tarea de Capistrano para lograr el resultado que necesitaba, como un encanto:
desc ''kill pgsql users so database can be dropped''
task :kill_postgres_connections do
run ''echo "SELECT pg_terminate_backend(procpid) FROM pg_stat_activity WHERE datname=/'database_name/';" | psql -U postgres''
end
Esto supone que el auth_method para el usuario postgres está configurado como ''trust'' en pg_hba.conf
Luego puede llamarlo en su tarea de implementación después de update_code
y antes de migrate
after ''deploy:update_code'', ''kill_postgres_connections''
Simplemente puede hacer un "monkeypatch" en el código ActiveRecord que hace que se caiga.
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 rieles 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/ )