【问题标题】:Why not use shared ActiveRecord connections for Rspec + Selenium?为什么不对 Rspec + Selenium 使用共享的 ActiveRecord 连接?
【发布时间】:2012-01-08 00:02:22
【问题描述】:

似乎最普遍接受的处理 Selenium 和测试的方法是避免使用事务性固定装置,然后在测试/场景之间使用诸如 database_cleaner 之类的东西。我最近遇到了以下article,它建议执行以下操作:

spec_helper.rb

class ActiveRecord::Base
  mattr_accessor :shared_connection
  @@shared_connection = nil

  def self.connection
    @@shared_connection || retrieve_connection
  end
end

# Forces all threads to share the same connection. This works on
# Capybara because it starts the web server in a thread.
ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection

这似乎比其他选项更能提高性能。有没有人有任何理由不应该使用它?

【问题讨论】:

    标签: ruby-on-rails ruby rspec capybara


    【解决方案1】:

    其实也有问题。例如,如果您使用 gem mysql2,您将开始看到一些错误,例如:

    Mysql2::Error This connection is still waiting for a result
    

    请改用这个。它是 Mike Perham 写的,全部归功于他。

    class ActiveRecord::Base
      mattr_accessor :shared_connection
      @@shared_connection = nil
    
      def self.connection
        @@shared_connection || ConnectionPool::Wrapper.new(:size => 1) { retrieve_connection }
      end
    end
    
    ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
    

    您还需要安装 gem connection_pool。 这将使您免于许多麻烦。

    【讨论】:

    【解决方案2】:

    此解决方案由 Jose Valim 编写 - 在 Rails 社区中备受推崇,并且是 Rails 核心团队的成员。如果有问题,我怀疑他会推荐使用它。我个人没有任何问题。

    请注意,如果您使用 Spork,则需要在 each_run 块中才能工作。

    FWIW - 我在 Postgres 上的上述补丁中遇到了间歇性水豚测试问题。 @hsgubert 下面的 Mike Perham 解决方案似乎已经解决了这些问题。我现在正在使用该解决方案。

    【讨论】:

    • 这并不是真正的答案,而是诉诸权威。
    【解决方案3】:

    DatabaseCleaner gem 自述文件这样回答您“为什么不”的问题:

    一种常见的方法是强制所有进程使用相同的数据库连接 (common ActiveRecord hack),但据报道这种方法会导致不确定性故障。

    【讨论】:

      【解决方案4】:

      我在使用您在我的 spec_helper.rb 文件中提到的代码时遇到了问题。

      当您的测试依赖于使用与多个数据库的连接时会发生什么?运行测试时,我需要连接两个数据库。我做了一个简单的测试来检查我建立的数据库连接发生了什么。

      class ActiveRecord::Base
         mattr_accessor :shared_connection
         @@shared_connection = nil
      
         def self.connection
           @@shared_connection || retrieve_connection
        end
      end
      
      # Forces all threads to share the same connection. This works on
      # Capybara because it starts the web server in a thread.
      puts "First Record cxn: #{FirstDatabase::Record.connection}"
      # => First Record cxn: #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0xe59b524>
      puts "AR Base cxn: #{ActiveRecord::Base.connection}"
      # => AR Base cxn: #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0xc52761c>
      ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
      
      puts "First Record cxn: #{FirstDatabase::Record.connection}"
      # => First Record cxn: #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0xc52761c>
      puts "AR Base cxn: #{ActiveRecord::Base.connection}"
      # => AR Base cxn: #<ActiveRecord::ConnectionAdapters::Mysql2Adapter:0xc52761c>
      

      如您所见,在调用共享连接方法之前,我有两个不同的数据库连接。之后,共享连接方法调用,我只有一个。

      因此,任何需要转到第二个数据库连接来检索信息的测试都会失败。 :(

      我将发布这个问题,看看是否有人找到了解决方案。

      【讨论】:

      • 当我将该代码转储到我的 ruby​​ 脚本中时,我得到了这个。 ruby(43221,0x109043000) malloc: *** error for object 0x7f915136e8c0: pointer being free was not assigned 我认为这是一个缺陷。
      【解决方案5】:

      我自己只是在做一些阅读。我发现了你在这篇博文中分享的 sn-p:

      http://blog.plataformatec.com.br/2011/12/three-tips-to-improve-the-performance-of-your-test-suite/

      为了直接回答您的问题,database cleaner github page 警告说它可能“导致非确定性故障”。我会继续使用它,但如果您开始遇到奇怪的故障,也许这是一个开始寻找的好地方。

      【讨论】:

        【解决方案6】:

        这篇文章的结尾有一件好事。它可以解释为什么当我尝试使用非常简单的线程脚本时会出现 MALLOC 错误。

        http://apidock.com/rails/ActiveRecord/Base/connection

        leente - March 15, 2011 0 thanks
        Don't cache it!
        
        Don’t store a connection in a variable, because another thread might try to use it when it’s already checked back in into the connection pool. See: ActiveRecord::ConnectionAdapters::ConnectionPool
        
        connection = ActiveRecord::Base.connection
        
        threads = (1..100).map do
          Thread.new do
            begin
              10.times do
                connection.execute("SELECT SLEEP(1)")  # WRONG
                ActiveRecord::Base.connection.execute("SELECT SLEEP(1)")  # CORRECT
              end
              puts "success"
            rescue => e
              puts e.message
            end
          end
        end
        
        threads.each(&:join)
        

        【讨论】:

          猜你喜欢
          • 2021-04-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-10-31
          • 2020-01-01
          • 2014-12-17
          相关资源
          最近更新 更多