ほぼ無知な分野ですので、よろしくお願いします。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 以上の失敗があります。また、再作成されたテスト DB を完全に削除しました。運もありません。
接続プールなどに関する多くのスレッドを読みましたが、何が起こっているのかさえ診断する方法がわかりません。私が現在知っている事実は次のとおりです。
- Postgresql の使用
- 開発環境は私が知る限り正常に動作します
- すべてが正常に機能していた時期から現在まで、私が認識している環境に変更やアップグレードを行っていません。データベースの移行さえありません。モデル、ビュー、およびコントローラーのコードを変更するだけです。前述したように、以前のコミットに戻っても何も修正されません。
config.use_transactional_fixtures = false
Seleniumを介してajax機能をテストしているため、spec_helper.rbで。- ただし、特定のテスト セットに Selenium が使用されているかどうかに関係なく、テストは失敗します。Selenium を使用していないテストだけを実行しても、20 回程度のテストの後で失敗が始まります。
トランザクション フィクスチャの代わりに、次の構成で Database Cleaner を使用しています。
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
アプリケーションの他の多くの場所で、この正確なパターン (さまざまな電子メールで) を使用しましたが、そのすべてがテストされています。何らかの理由で、この特定の 1 つがデータベースのタイムアウト エラーを引き起こしています。なぜこれが起こっているのかについてのアイデアは大歓迎です。
更新 このインスタンスでスレッドがどのように機能するかを理解する段階にないので、これ以外に問題の正確な原因はわかりません:私が読んだことから、実行をプログラムで制御することは非常に困難ですこうして作られたスレッド。しかし、私は解決策を見つけました。上記のブロックの代わりに、ブロックを次のように変更しました。
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
したがって、私は基本的に、開発用とは異なるテスト用のコードを実行しています。テスト用の新しいスレッドはありません。それは悪い考えだと思いますが、本当の問題がどこにあるかを理解できるまで (何らかの理由で本質的に失敗しないテスト、または失敗したテストを強制しないスレッドをまだ使用しているコード)、これは私が行く必要があるものです。
最終更新
メールを非同期で送信するThread.new
方法をやめ、代わりに Sidekiq を実装しました。もう少し作業が必要ですが、うまく機能し、問題なくテストされます...