PERF: Optimize themes:update task (#29290)

- Add concurrency when running on multisite clusters (default 10, configurable via THEME_UPDATE_CONCURRENCY env)

- Add a version cache for the duration of the rake task. This avoids duplicating work when many sites in the cluster have the same theme installed, and it is already up-to-date

- Updates output to be more concurrent friendly (all `puts`, no `print`)
This commit is contained in:
David Taylor 2024-10-21 12:36:40 +01:00 committed by GitHub
parent a5497b74be
commit b3b0695bb1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 25 additions and 7 deletions

View File

@ -243,8 +243,6 @@ if ENV["IMPORT"] == "1"
gem "reverse_markdown"
gem "tiny_tds"
gem "csv"
gem "parallel", require: false
end
group :generic_import, optional: true do
@ -289,3 +287,5 @@ group :migrations, optional: true do
end
gem "dry-initializer", "~> 3.1"
gem "parallel"

View File

@ -677,6 +677,7 @@ DEPENDENCIES
omniauth-google-oauth2
omniauth-oauth2
omniauth-twitter
parallel
parallel_tests
pg
pry-byebug

View File

@ -60,7 +60,7 @@ task "themes:install:archive" => :environment do |task, args|
RemoteTheme.update_zipped_theme(filename, File.basename(filename), update_components:)
end
def update_themes
def update_themes(version_cache: Concurrent::Map.new)
Theme
.includes(:remote_theme)
.where(enabled: true, auto_update: true)
@ -69,16 +69,26 @@ def update_themes
theme.transaction do
remote_theme = theme.remote_theme
next if remote_theme.blank? || remote_theme.remote_url.blank?
prefix = "[db:#{RailsMultisite::ConnectionManagement.current_db}] '#{theme.name}' - "
puts "#{prefix} checking..."
print "Checking '#{theme.name}' for '#{RailsMultisite::ConnectionManagement.current_db}'... "
cache_key =
"#{remote_theme.remote_url}:#{remote_theme.branch}:#{Digest::SHA256.hexdigest(remote_theme.private_key.to_s)}"
if version_cache[cache_key] == remote_theme.remote_version && !remote_theme.out_of_date?
puts "#{prefix} up to date (cached from previous lookup)"
next
end
remote_theme.update_remote_version
version_cache.put_if_absent(cache_key, remote_theme.remote_version)
if remote_theme.out_of_date?
puts "updating from #{remote_theme.local_version[0..7]} to #{remote_theme.remote_version[0..7]}"
puts "#{prefix} updating from #{remote_theme.local_version[0..7]} to #{remote_theme.remote_version[0..7]}"
remote_theme.update_from_remote(already_in_transaction: true)
else
puts "up to date"
puts "#{prefix} up to date"
end
if remote_theme.last_error_text.present?
@ -99,7 +109,14 @@ task "themes:update": %w[environment assets:precompile:theme_transpiler] do
if ENV["RAILS_DB"].present?
update_themes
else
RailsMultisite::ConnectionManagement.each_connection { update_themes }
version_cache = Concurrent::Map.new
concurrency = ENV["THEME_UPDATE_CONCURRENCY"]&.to_i || 10
puts "Updating themes with concurrency: #{concurrency}" if concurrency > 1
Parallel.each(RailsMultisite::ConnectionManagement.all_dbs, in_threads: concurrency) do |db|
RailsMultisite::ConnectionManagement.with_connection(db) { update_themes(version_cache:) }
end
end
end