【问题标题】:Capistrano with PostgreSQL, error: database is being accessed by other usersCapistrano 与 PostgreSQL,错误:其他用户正在访问数据库
【发布时间】:2012-10-07 03:06:24
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: ruby-on-rails postgresql capistrano


    【解决方案1】:

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

    SELECT pid FROM pg_stat_activity where pid <> pg_backend_pid();
    

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

    SELECT pg_terminate_backend($1);
    

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

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

    更新:合并 cmets 并表示为 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
    

    【讨论】:

    • 我推荐REVOKE CONNECT ON DATABASE dbname FROM public;,然后是SELECT pg_terminate_backend(pid) FROM pg_stat_activity where pid &lt;&gt; pg_backend_pid();,然后是DROP DATABASE dbname;。这消除了新客户端不断连接的竞争,因此您永远没有足够的时间来删除数据库。
    • 另一个建议:首先,运行“ALTER DATABASE dbname CONNECTION LIMIT 0;”然后终止查询。如果您使用 psql,将连接限制设置为 0 不会成为连接数据库的障碍。
    • 在我使用的版本(9.1.9)中,pid不是列名,而是procpid是:SELECT procpid FROM pg_stat_activity where procpid pg_backend_pid();
    • 我刚收到ERROR: there is no parameter $1
    • @mkataja $1 是您希望终止的后端 pid 的占位符。如果您只是使用 psql 执行 sql 语句,则将 pid 号替换为 $1。如果您正在编写程序,大多数 db 接口库都提供将参数值绑定到包含 $x 占位符的语句的方法,因此使用它来提供包含要终止的 pid 的整数。
    【解决方案2】:

    您可以简单地对执行删除操作的 ActiveRecord 代码进行猴子补丁。

    对于 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
    

    对于 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
    

    (来自:http://www.krautcomputing.com/blog/2014/01/10/how-to-drop-your-postgres-database-with-rails-4/

    【讨论】:

      【解决方案3】:

      我已将 dbenhur's answer 与此 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
      

      这假定用户 postgres 的 auth_method 在 pg_hba.conf 中设置为“信任”

      然后您可以在 update_codemigrate 之前的部署任务中调用它

      after 'deploy:update_code', 'kill_postgres_connections'
      

      【讨论】:

      • 顺便说一句,您不需要 echo 和 pipe 将语句发送到 psql。只需使用-c cmdline 选项。
      • @dbenhur : 你能用包含的 -c 选项更新你的评论吗?
      猜你喜欢
      • 1970-01-01
      • 2011-01-23
      • 1970-01-01
      • 2012-12-31
      • 2022-06-16
      • 1970-01-01
      • 2017-12-01
      • 2018-08-20
      • 2019-02-01
      相关资源
      最近更新 更多