为什么不为 Rspec 使用共享 ActiveRecord 连接?硒?

发布于 2024-12-25 15:15:59 字数 706 浏览 3 评论 0原文

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

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

这似乎比其他替代方案加载更好的性能。有人有任何理由不应该使用它吗?

It seems the most commonly accepted way to deal with Selenium and tests is to avoid using transactional fixtures and then using something like database_cleaner between tests/scenarios. I recently ran into the following article which suggested doing the following:

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

This seems loads better for performance than the alternatives. Does anyone have any reason why this shouldn't be used?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

东北女汉子 2025-01-01 15:15:59

其实这里面是有问题的。例如,如果您使用 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
这将使您免于许多头痛。

Actually there are issues with it. If you use the gem mysql2, for example, you'll start seeing some errors like:

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

Please use this instead. It was written by Mike Perham, all credits to him.

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

You'll need to install gem connection_pool too.
This will spare you from many headaches.

醉态萌生 2025-01-01 15:15:59

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

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

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

This solution was written by Jose Valim - well respected in the Rails community and a member of the Rails core team. I doubt he would recommend using it if there were issues with it. I personally haven't had any issues.

Just be aware that if you use Spork this needs to be in the each_run block to work.

FWIW - I have had intermittent capybara test issues with the above patch on Postgres. The Mike Perham solution that @hsgubert has below appears to have solved those issues. I am now use that solution.

若言繁花未落 2025-01-01 15:15:59

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

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

The DatabaseCleaner gem readme answers your "why not" question this way:

One common approach is to force all processes to use the same database connection (common ActiveRecord hack) however this approach has been reported to result in non-deterministic failures.

情深如许 2025-01-01 15:15:59

我在使用您在我的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>

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

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

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

I have encountered a problem using the code you mentioned in my spec_helper.rb file.

What happens when your tests depend on using connections to multiple databases? I have two databases I need to connect to when I run my tests. I did a simple test to check what was happening to the database connections I establish.

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>

As you can see, before I call the shared connection method, I have two different database connections. After, the shared connection method call, I have only one.

So any test that requires going to the second database connection to retrieve information will fail. :(

I'm going to post this problem and see if anyone has arrived at a solution.

洒一地阳光 2025-01-01 15:15:59

我自己只是做了一点阅读。我发现了您在此博文中分享的片段:

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

到直接回答你的问题,数据库清理器 github 页面警告说它可能“导致非确定性故障”。我会直接使用它,但如果您开始遇到奇怪的故障,也许这是一个开始寻找的好地方。

I was just doing a little reading on this myself. I discovered the snippet you shared here in this blog post:

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

To answer your question directly, the database cleaner github page cautions that it can " result in non-deterministic failures". I'd go right ahead and use it, but if you start running into weird failures, maybe this is a good place to start looking.

三人与歌 2025-01-01 15:15:59

这篇文章的最后有一件好事。它可以解释为什么当我尝试一个非常简单的线程脚本时出现 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)

There's a good thing at the end of this post. It may explain why I get a MALLOC error when I attempt to a very simple threading script.

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)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文