DEV: Preload all models schema cache before running system tests (#25008)
Why this change? When running system tests with all official plugins installed, we have encountered instances where the system tests will hang. When dumping the backtraces of the threads, we can see that the main thread running the tests is stuck in a deadlock with the puma thread while serving a request. The deadlock happens when the main thread acquires the `ActiveSupport::Concurrency::LoadInterlockAwareMonitor` lock first in `ActiveRecord::ConnectionAdapters::AbstractAdapter` before acquring another `Monitor` lock in `ActiveRecord::ModelSchema`. In the Puma thread, it acquires the `Monitor` lock in `ActiveRecord::ModelSchema` first before acquring the `ActiveSupport::Concurrency::LoadInterlockAwareMonitor` lock. What does this change do? To workaround this problem, we will preload all model schema cache before running system tests such that the `Monitor` lock in `ActiveRecord::ModelSchema` will not be acquired.
This commit is contained in:
parent
7cad69e6ef
commit
d3625f2288
|
@ -239,21 +239,6 @@ RSpec.configure do |config|
|
|||
raise "There are pending migrations, run RAILS_ENV=test bin/rake db:migrate"
|
||||
end
|
||||
|
||||
# Use a file system lock to get `selenium-manager` to download the `chromedriver` binary that is required for
|
||||
# system tests to support running system tests in multiple processes. If we don't download the `chromedriver` binary
|
||||
# before running system tests in multiple processes, each process will end up calling the `selenium-manager` binary
|
||||
# to download the `chromedriver` binary at the same time but the problem is that the binary is being downloaded to
|
||||
# the same location and this can interfere with the running tests in another process.
|
||||
#
|
||||
# The long term fix here is to get `selenium-manager` to download the `chromedriver` binary to a unique path for each
|
||||
# process but the `--cache-path` option for `selenium-manager` is currently not supported in `selenium-webdriver`.
|
||||
if !File.directory?("~/.cache/selenium")
|
||||
File.open("#{Rails.root}/tmp/chrome_driver_flock", "w") do |file|
|
||||
file.flock(File::LOCK_EX)
|
||||
`#{Selenium::WebDriver::SeleniumManager.send(:binary)} --browser chrome`
|
||||
end
|
||||
end
|
||||
|
||||
Sidekiq.error_handlers.clear
|
||||
|
||||
# Ugly, but needed until we have a user creator
|
||||
|
@ -499,8 +484,37 @@ RSpec.configure do |config|
|
|||
# Match the request hostname to the value in `database.yml`
|
||||
config.before(:each, type: %i[request multisite system]) { host! "test.localhost" }
|
||||
|
||||
last_driven_by = nil
|
||||
system_tests_initialized = false
|
||||
|
||||
config.before(:each, type: :system) do |example|
|
||||
if !system_tests_initialized
|
||||
# Use a file system lock to get `selenium-manager` to download the `chromedriver` binary that is required for
|
||||
# system tests to support running system tests in multiple processes. If we don't download the `chromedriver` binary
|
||||
# before running system tests in multiple processes, each process will end up calling the `selenium-manager` binary
|
||||
# to download the `chromedriver` binary at the same time but the problem is that the binary is being downloaded to
|
||||
# the same location and this can interfere with the running tests in another process.
|
||||
#
|
||||
# The long term fix here is to get `selenium-manager` to download the `chromedriver` binary to a unique path for each
|
||||
# process but the `--cache-path` option for `selenium-manager` is currently not supported in `selenium-webdriver`.
|
||||
if !File.directory?("~/.cache/selenium")
|
||||
File.open("#{Rails.root}/tmp/chrome_driver_flock", "w") do |file|
|
||||
file.flock(File::LOCK_EX)
|
||||
`#{Selenium::WebDriver::SeleniumManager.send(:binary)} --browser chrome`
|
||||
end
|
||||
end
|
||||
|
||||
# On Rails 7, we have seen instances of deadlocks between the lock in [ActiveRecord::ConnectionAdapaters::AbstractAdapter](https://github.com/rails/rails/blob/9d1673853f13cd6f756315ac333b20d512db4d58/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb#L86)
|
||||
# and the lock in [ActiveRecord::ModelSchema](https://github.com/rails/rails/blob/9d1673853f13cd6f756315ac333b20d512db4d58/activerecord/lib/active_record/model_schema.rb#L550).
|
||||
# To work around this problem, we are going to preload all the model schemas before running any system tests so that
|
||||
# the lock in ActiveRecord::ModelSchema is not acquired at runtime. This is a temporary workaround while we report
|
||||
# the issue to the Rails.
|
||||
ActiveRecord::Base.connection.data_sources.map do |table|
|
||||
ActiveRecord::Base.connection.schema_cache.add(table)
|
||||
end
|
||||
|
||||
system_tests_initialized = true
|
||||
end
|
||||
|
||||
driver = [:selenium]
|
||||
driver << :mobile if example.metadata[:mobile]
|
||||
driver << :chrome
|
||||
|
|
Loading…
Reference in New Issue