Commit ec39a1d6 authored by Mayra Cabrera's avatar Mayra Cabrera

Schedule namespace aggregation in other contexts

Schedules a Namespace::AggregationSchedule worker if some of the project
statistics are refreshed.

The worker is only executed if the feature flag is enabled.
parent ededb334
# frozen_string_literal: true # frozen_string_literal: true
class ProjectStatistics < ApplicationRecord class ProjectStatistics < ApplicationRecord
include AfterCommitQueue
belongs_to :project belongs_to :project
belongs_to :namespace belongs_to :namespace
...@@ -15,6 +17,7 @@ class ProjectStatistics < ApplicationRecord ...@@ -15,6 +17,7 @@ class ProjectStatistics < ApplicationRecord
COLUMNS_TO_REFRESH = [:repository_size, :wiki_size, :lfs_objects_size, :commit_count].freeze COLUMNS_TO_REFRESH = [:repository_size, :wiki_size, :lfs_objects_size, :commit_count].freeze
INCREMENTABLE_COLUMNS = { build_artifacts_size: %i[storage_size], packages_size: %i[storage_size] }.freeze INCREMENTABLE_COLUMNS = { build_artifacts_size: %i[storage_size], packages_size: %i[storage_size] }.freeze
NAMESPACE_RELATABLE_COLUMNS = [:repository_size, :wiki_size, :lfs_objects_size].freeze
scope :for_project_ids, ->(project_ids) { where(project_id: project_ids) } scope :for_project_ids, ->(project_ids) { where(project_id: project_ids) }
...@@ -22,13 +25,17 @@ class ProjectStatistics < ApplicationRecord ...@@ -22,13 +25,17 @@ class ProjectStatistics < ApplicationRecord
repository_size + lfs_objects_size repository_size + lfs_objects_size
end end
def refresh!(only: nil) def refresh!(only: [])
COLUMNS_TO_REFRESH.each do |column, generator| COLUMNS_TO_REFRESH.each do |column, generator|
if only.blank? || only.include?(column) if only.empty? || only.include?(column)
public_send("update_#{column}") # rubocop:disable GitlabSecurity/PublicSend public_send("update_#{column}") # rubocop:disable GitlabSecurity/PublicSend
end end
end end
if only.empty? || only.any? { |column| NAMESPACE_RELATABLE_COLUMNS.include?(column) }
schedule_namespace_aggregation_worker
end
save! save!
end end
...@@ -81,4 +88,18 @@ class ProjectStatistics < ApplicationRecord ...@@ -81,4 +88,18 @@ class ProjectStatistics < ApplicationRecord
update_all(updates.join(', ')) update_all(updates.join(', '))
end end
private
def schedule_namespace_aggregation_worker
run_after_commit do
next unless schedule_aggregation_worker?
Namespaces::ScheduleAggregationWorker.perform_async(project.namespace_id)
end
end
def schedule_aggregation_worker?
Feature.enabled?(:update_statistics_namespace, project&.root_ancestor)
end
end end
...@@ -135,6 +135,49 @@ describe ProjectStatistics do ...@@ -135,6 +135,49 @@ describe ProjectStatistics do
expect(statistics.wiki_size).to eq(0) expect(statistics.wiki_size).to eq(0)
end end
end end
context 'when the column is namespace relatable' do
let(:namespace) { create(:group) }
let(:project) { create(:project, namespace: namespace) }
context 'when the feature flag is off' do
it 'does not schedule the aggregation worker' do
stub_feature_flags(update_statistics_namespace: false, namespace: namespace)
expect(Namespaces::ScheduleAggregationWorker)
.not_to receive(:perform_async)
statistics.refresh!(only: [:lfs_objects_size])
end
end
context 'when the feature flag is on' do
it 'schedules the aggregation worker' do
expect(Namespaces::ScheduleAggregationWorker)
.to receive(:perform_async)
statistics.refresh!(only: [:lfs_objects_size])
end
end
context 'when no argument is passed' do
it 'schedules the aggregation worker' do
expect(Namespaces::ScheduleAggregationWorker)
.to receive(:perform_async)
statistics.refresh!
end
end
end
context 'when the column is not namespace relatable' do
it 'does not schedules an aggregation worker' do
expect(Namespaces::ScheduleAggregationWorker)
.not_to receive(:perform_async)
statistics.refresh!(only: [:commit_count])
end
end
end end
describe '#update_commit_count' do describe '#update_commit_count' do
......
...@@ -36,6 +36,11 @@ describe ProjectCacheWorker do ...@@ -36,6 +36,11 @@ describe ProjectCacheWorker do
end end
context 'with an existing project' do context 'with an existing project' do
before do
lease_key = "namespace:namespaces_root_statistics:#{project.namespace_id}"
stub_exclusive_lease_taken(lease_key, timeout: Namespace::AggregationSchedule::DEFAULT_LEASE_TIMEOUT)
end
it 'refreshes the method caches' do it 'refreshes the method caches' do
expect_any_instance_of(Repository).to receive(:refresh_method_caches) expect_any_instance_of(Repository).to receive(:refresh_method_caches)
.with(%i(readme)) .with(%i(readme))
...@@ -81,6 +86,10 @@ describe ProjectCacheWorker do ...@@ -81,6 +86,10 @@ describe ProjectCacheWorker do
expect(UpdateProjectStatisticsWorker).not_to receive(:perform_in) expect(UpdateProjectStatisticsWorker).not_to receive(:perform_in)
expect(Namespaces::ScheduleAggregationWorker)
.not_to receive(:perform_async)
.with(project.namespace_id)
worker.update_statistics(project, statistics) worker.update_statistics(project, statistics)
end end
end end
...@@ -98,6 +107,11 @@ describe ProjectCacheWorker do ...@@ -98,6 +107,11 @@ describe ProjectCacheWorker do
.with(lease_timeout, project.id, statistics) .with(lease_timeout, project.id, statistics)
.and_call_original .and_call_original
expect(Namespaces::ScheduleAggregationWorker)
.to receive(:perform_async)
.with(project.namespace_id)
.twice
worker.update_statistics(project, statistics) worker.update_statistics(project, statistics)
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment