Sudden inexplicable active record connection timeouts while testing with RSPEC

我们两清 提交于 2019-12-07 07:15:04

问题


This is an area I know almost nothing about, so apologies in advance. I have a suite of over 800 rspec tests. Suddenly and inexplicably when running the whole set or just particular test files, after just a few of these, (say 20 or so, although it's never exactly the same number), every single test begins to fail with the same error:

 Failure/Error: Unable to find matching line from backtrace
 ActiveRecord::ConnectionTimeoutError:
   could not obtain a database connection within 5.000 seconds (waited 5.000 seconds)

In a typical run, I'll start getting these errors after 20 or so request tests, and the remaining 780+ tests all fail with the exact same error above. I've tried going back to a previous git commit and branch that previously tested perfectly. No luck — still 780+ failures. Also completely dropped an recreated test DB. Also no luck.

I've read many threads about connection pools etc., but I'm afraid I have no idea how to diagnose even what's going on. Here are the facts as I know them right now:

  • Using Postgresql
  • Development environment works fine as far as I can tell
  • In between the time everything was working fine and now, I've made no changes/upgrades to the environment that I'm aware of. Not even any database migrations. Merely changes to model, view and controller code. And as I mentioned, going back to previous commits doesn't fix anything.
  • config.use_transactional_fixtures = false in spec_helper.rb because I'm testing ajax functionality via Selenium.
  • Tests, however, fail regardless of whether Selenium is being used for the particular set of tests. Even if I run only tests that are not using Selenium, failures still start after 20 or so tests.

Instead of transactional fixtures, I am using Database Cleaner with the following configuration:

  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end

  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end

  config.before(:each, :js => true) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
    DatabaseCleaner.start
  end

  config.after(:each) do
    DatabaseCleaner.clean
  end

Any ideas what's going on here? And more specifically, any ideas where I should be looking to see what the problem is? I have almost no experience dealing with ActiveRecord issues of this type and I don't even know where to start.

Update While I still don't know exactly why this is happening, I do know specifically what code is causing it. In a recent commit I had added sending of a notification email in a new thread. Here's the code:

    def teacher_notification_email
      Thread.new do
        UserMailer.accepted_parent_invitation_email(@parent_profile).deliver
        ActiveRecord::Base.connection.close
      end
    end

I've used this exact pattern (with different emails) in many other places in the application, all of which get tested. For some reason, this particular one is causing database timeout errors. Any ideas on why this is happening are welcome.

Update Since I'm not at a stage where I understand how threading works in this instance, I don't know the exact source of the problem, other than this: from what I've read, it's very hard to programmatically control the execution of a thread created in this way. However, I've found a solution. Instead of the above block, I've changed the block to the following:

    def teacher_notification_email
      if Rails.env.test?
        UserMailer.accepted_parent_invitation_email(@parent_profile).deliver
      else
        Thread.new do
          UserMailer.accepted_parent_invitation_email(@parent_profile).deliver
          ActiveRecord::Base.connection.close
        end
      end
    end

So I'm basically running different code for test than development - no new thread for test. I'm assuming that's a bad idea, but until I can understand where the real problem is (a test that doesn't inherently fail for whatever reason, or code that still uses the thread that doesn't force a failed test), this is what I need to go with.

Final Update

I've dropped the Thread.new method of asynchronously sending emails and have, instead, implemented Sidekiq. It's a little more work, but it works well and tests fine...


回答1:


It seems this is related to touching active record inside a spawned thread. It looks like the db connection doesn't get returned to the pool until it is reaped. I've been able to resolve this issue by explicitly asking for a connection ahead of time and closing it after I'm done. Try this:

Thread.new do
    ActiveRecord::Base.connection_pool.with_connection do |conn|
        UserMailer.accepted_parent_invitation_email(@parent_profile).deliver
    end
end


来源:https://stackoverflow.com/questions/24270994/sudden-inexplicable-active-record-connection-timeouts-while-testing-with-rspec

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!