Capistrano与PostgreSQL,错误:其他用户正在访问数据库

Gra*_*ett 30 postgresql capistrano ruby-on-rails

我有一个Rails应用程序,它使用PostgreSQL作为后端,具有试图模仿生产的证书环境,除了它需要定期重置数据库以进行QA.

当我db:reset在部署期间尝试从Capistrano任务执行时,我收到错误:

ERROR: database "database_name" is being accessed by other users

并且数据库不能作为重置任务的一部分被删除,从而导致部署失败.有没有办法可以从Capistrano重置数据库连接,这样我就可以成功删除表格?从Capistrano任务管道SQL到psql可能会有效,但我想知道是否有更好的方法来解决这个问题.

dbe*_*hur 55

使用PostgreSQL,您可以发出以下语句来返回除此之外的所有打开连接的后端pids:

SELECT pid FROM pg_stat_activity where pid <> pg_backend_pid();
Run Code Online (Sandbox Code Playgroud)

然后,您可以向每个后端发出终止请求

SELECT pg_terminate_backend($1);
Run Code Online (Sandbox Code Playgroud)

将从第一个语句返回的pid绑定到每个pg_terminate_backend exec.

如果其他连接未使用与您相同的用户,则必须以超级用户身份连接才能成功发出终止.

更新:合并评论并表达为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
Run Code Online (Sandbox Code Playgroud)

  • 在我正在使用的版本(9.1.9)中,pid不是列名,但是procpid是:SELECT procpid FROM pg_stat_activity where procpid <> pg_backend_pid(); (6认同)
  • 我建议`REVOKE CONNECT ON DATABASE dbname FROM public;`然后`SELECT pg_terminate_backend(pid)FROM pg_stat_activity其中pid <> pg_backend_pid();`后跟`DROP DATABASE dbname;`.这消除了新客户端不断连接的竞争,因此您永远不会有足够的时间来DROP db. (2认同)

Gra*_*ett 5

我把dbenhur的答案与这个Capistrano任务结合起来,以达到我需要的效果,就像一个魅力:

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
Run Code Online (Sandbox Code Playgroud)

这假设用户postgres的auth_method在pg_hba.conf中设置为"trust"

然后,您可以在部署任务update_code之前和之后调用它migrate

after 'deploy:update_code', 'kill_postgres_connections'
Run Code Online (Sandbox Code Playgroud)