discourse/app/services/admin_dashboard_section_loader.rb
Natalie Tay da2e0fe3bc
PERF: Parallelize section loading in new dashboard (#40970)
Since we're loading different sections at once on the dash, it might
make sense to load them in parallel.

| Metric | Current parallel | Baseline serial | Delta |
|---|---:|---:|---:|
| Runs | 2543, 1558, 1693, 1336, 1383 ms | 3104, 1985, 2147, 2428, 2372
ms | |
| Min | 1336 ms | 1985 ms | -649 ms |
| Median | 1558 ms | 2372 ms | -814 ms (-34.3%) |
| Average | 1703 ms | 2407 ms | -704 ms (-29.2%) |
| Max | 2543 ms | 3104 ms | -561 ms |
2026-06-17 16:29:10 +08:00

72 lines
1.9 KiB
Ruby
Vendored

# frozen_string_literal: true
class AdminDashboardSectionLoader
POOL_SIZE = AdminDashboardSectionConfiguration::KNOWN_SECTIONS.size
def self.build(section_ids:, current_user:, start_date:, end_date:)
new(
section_ids: section_ids,
current_user: current_user,
start_date: start_date,
end_date: end_date,
).build
end
def self.thread_pool
@thread_pool ||=
Scheduler::ThreadPool.new(min_threads: 0, max_threads: POOL_SIZE, idle_time: 30)
end
def initialize(section_ids:, current_user:, start_date:, end_date:)
@section_ids = section_ids
@current_user = current_user
@start_date = start_date
@end_date = end_date
end
def build
results = Queue.new
section_ids.each do |id|
self.class.thread_pool.post do
results << { id: id, data: section_data(id, current_user) }
rescue StandardError => e
results << { id: id, error: e }
end
end
results_by_id = {}
section_ids.size.times do
result = results.pop
raise result[:error] if result[:error]
results_by_id[result[:id]] = result
end
section_ids.map { |id| results_by_id.fetch(id) }
end
private
attr_reader :section_ids, :current_user, :start_date, :end_date
def section_data(id, user)
case id
when "highlights"
AdminDashboardHighlights.build(start_date: start_date, end_date: end_date)
when "traffic"
AdminDashboardSiteTraffic.build(
start_date: start_date,
end_date: end_date,
guardian: user.guardian,
)
when "engagement"
AdminDashboardEngagement.build(start_date: start_date, end_date: end_date, current_user: user)
when "reports"
AdminDashboard::Reports::Section.build(guardian: user.guardian)
when "search"
AdminDashboardSearch.build(start_date: start_date, end_date: end_date)
end
end
end