这是我几乎一无所知的地方,所以请提前道歉。我有一套超过800个rspec测试。在运行整个集合或仅仅是特定的测试文件时突然而且莫名其妙地,在这些之后,(例如20个左右,虽然它的数字从不完全相同),每个单独的测试都会以相同的错误开始失败:
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)
在典型的运行中,我会在20次左右的请求测试后开始收到这些错误,其余的780+测试都会因上述完全相同的错误而失败。我已经尝试过回到之前测试完美的git提交和分支。没有运气 - 仍有780多个失败。还完全删除了重新创建的测试数据库。也没有运气。
我已经阅读了许多关于连接池等的线索,但我担心我不知道如何诊断甚至是什么。以下是我现在所知道的事实:
config.use_transactional_fixtures = false
因为我正在通过Selenium测试ajax功能。我使用数据库清理程序而不是事务夹具,具有以下配置:
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
有什么想法在这里发生了什么?更具体地说,我应该在哪些想法看看问题是什么?我几乎没有处理此类ActiveRecord问题的经验,我甚至不知道从哪里开始。
更新虽然我仍然不知道为什么会发生这种情况,但我确实知道导致它的代码是什么。在最近的提交中,我添加了在新线程中发送通知电子邮件。这是代码:
def teacher_notification_email
Thread.new do
UserMailer.accepted_parent_invitation_email(@parent_profile).deliver
ActiveRecord::Base.connection.close
end
end
我已经在应用程序的许多其他地方使用了这个确切的模式(使用不同的电子邮件),所有这些都经过测试。出于某种原因,这个特定的原因导致数据库超时错误。关于为什么会发生这种情况的任何想法都是受欢迎的。
更新 由于我还没有理解在这种情况下线程如何工作的阶段,我不知道问题的确切来源,除此之外:从我读过的内容,它&#39 ;很难以编程方式控制以这种方式创建的线程的执行。但是,我找到了解决方案。我没有将上述块改为以下块:
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
所以我基本上为测试而不是开发运行不同的代码 - 没有用于测试的新线程。我认为这是一个糟糕的主意,但直到我能够理解真正的问题在哪里(一个本身不会因任何原因而失败的测试,或者代码仍然使用的线程不是' ; t强制测试失败),这是我需要的。
最终更新
我已经放弃了异步发送电子邮件的Thread.new
方法,而是实施了Sidekiq。这是一项更多的工作,但它运作良好,测试得很好......
答案 0 :(得分:5)
这似乎与在生成的线程中触摸活动记录有关。看起来db连接在收到之前不会返回池中。我已经能够通过明确要求提前连接并在完成后关闭它来解决此问题。试试这个:
Thread.new do
ActiveRecord::Base.connection_pool.with_connection do |conn|
UserMailer.accepted_parent_invitation_email(@parent_profile).deliver
end
end