使用 zeus 进行 Cucumber 和 RSpec 测试:其他用户正在访问 Postgres其他用户、测试、Cucumber、zeus

2023-09-08 00:35:53 作者:百善孝当先。

In my Rails 3.2.13 app, I'm using Zeus. In the test environment I use PostgreSQL. When I run Cucumber and then RSpec (or the other way around), 9 out of 10 times I get the message:

PG::Error: ERROR:  database "bp_test" is being accessed by other users
DETAIL:  There are 1 other session(s) using the database.
: DROP DATABASE IF EXISTS "bp_test"

Tasks: TOP => db:test:load => db:test:purge
(See full trace by running task with --trace)

It takes a whole non-deterministic circus of trying to kill database connections to get this to work again, as described here. But this does not always work and is a big hassle as well. There must be a better solution for this. Does anyone know?

解决方案 评测 性价比最高的家用级NAS 玩客云怎么玩才更尽兴

Inspired by this answer, we created the following database.rake file. Where the original answer worked only for PostgreSQL 9.1, this one is modified to work for PostgreSQL 9.2 as well. The mechanism is not the prettiest: when the 9.1 command fails, it simply executes the 9.2 command. But the most important thing: it works!

#{Rails.root}/lib/tasks/databases.rake
# monkey patch ActiveRecord to avoid There are n other session(s) using the database.
def drop_database(config)
  case config['adapter']
  when /mysql/
    ActiveRecord::Base.establish_connection(config)
    ActiveRecord::Base.connection.drop_database config['database']
  when /sqlite/
    require 'pathname'
    path = Pathname.new(config['database'])
    file = path.absolute? ? path.to_s : File.join(Rails.root, path)

    FileUtils.rm(file)
  when /postgresql/
    begin
      ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
      ActiveRecord::Base.connection.select_all("select * from pg_stat_activity order by procpid;").each do |x|
        if config['database'] == x['datname'] && x['current_query'] =~ /<IDLE>/
          ActiveRecord::Base.connection.execute("select pg_terminate_backend(#{x['procpid']})")
        end
      end
      ActiveRecord::Base.connection.drop_database config['database']
    rescue # in PG 9.2 column procpid was renamed pid and the query status is checked not using 'current_query' but using 'state'
      ActiveRecord::Base.establish_connection(config.merge('database' => 'postgres', 'schema_search_path' => 'public'))
      ActiveRecord::Base.connection.select_all("select * from pg_stat_activity order by pid;").each do |x|
        if config['database'] == x['datname'] && x['state'] =~ /idle/
          ActiveRecord::Base.connection.execute("select pg_terminate_backend(#{x['pid']})")
        end
      end
      ActiveRecord::Base.connection.drop_database config['database']
    end
  end
end