diff options
author | Mayra Cabrera <mcabrera@gitlab.com> | 2019-07-02 17:44:39 +0300 |
---|---|---|
committer | Kamil TrzciĆski <ayufan@ayufan.eu> | 2019-07-02 17:44:39 +0300 |
commit | dfdfa913ba9cb74beb7adad0352c5efadec84494 (patch) | |
tree | 16d730e52e00d6f921087ec6531ab463447d09f8 /spec/workers | |
parent | e07ebe66af957c46e7c69329b3ab561bb539351b (diff) |
Includes logic to persist namespace statistics
- Add two new ActiveRecord models:
- RootNamespaceStoragestatistics will persist root namespace statistics
- NamespaceAggregationSchedule will save information when a new update
to the namespace statistics needs to be scheduled
- Inject into UpdateProjectStatistics concern a new callback that will
call an async job to insert a new row onto NamespaceAggregationSchedule
table
- When a new row is inserted a new job is scheduled. This job will
update call an specific service to update the statistics and after that
it will delete thee aggregated scheduled row
- The RefresherServices makes heavy use of arel to build composable
queries to update Namespace::RootStorageStatistics attributes.
- Add an extra worker to traverse pending rows on
NAmespace::AggregationSchedule table and schedule a worker for each one
of this rows.
- Add an extra worker to traverse pending rows on
NAmespace::AggregationSchedule table and schedule a worker for each one
of this rows
Diffstat (limited to 'spec/workers')
3 files changed, 189 insertions, 0 deletions
diff --git a/spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb b/spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb new file mode 100644 index 00000000000..b069b080531 --- /dev/null +++ b/spec/workers/namespaces/prune_aggregation_schedules_worker_spec.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Namespaces::PruneAggregationSchedulesWorker, '#perform', :clean_gitlab_redis_shared_state do + include ExclusiveLeaseHelpers + + let(:namespaces) { create_list(:namespace, 5, :with_aggregation_schedule) } + let(:timeout) { Namespace::AggregationSchedule::DEFAULT_LEASE_TIMEOUT } + + subject(:worker) { described_class.new } + + before do + allow(Namespaces::RootStatisticsWorker) + .to receive(:perform_async).and_return(nil) + + allow(Namespaces::RootStatisticsWorker) + .to receive(:perform_in).and_return(nil) + + namespaces.each do |namespace| + lease_key = "namespace:namespaces_root_statistics:#{namespace.id}" + stub_exclusive_lease(lease_key, timeout: timeout) + end + end + + it 'schedules a worker per pending aggregation' do + expect(Namespaces::RootStatisticsWorker) + .to receive(:perform_async).exactly(5).times + + expect(Namespaces::RootStatisticsWorker) + .to receive(:perform_in).exactly(5).times + + worker.perform + end +end diff --git a/spec/workers/namespaces/root_statistics_worker_spec.rb b/spec/workers/namespaces/root_statistics_worker_spec.rb new file mode 100644 index 00000000000..8dd74b96d49 --- /dev/null +++ b/spec/workers/namespaces/root_statistics_worker_spec.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Namespaces::RootStatisticsWorker, '#perform' do + let(:group) { create(:group, :with_aggregation_schedule) } + + subject(:worker) { described_class.new } + + context 'with a namespace' do + it 'executes refresher service' do + expect_any_instance_of(Namespaces::StatisticsRefresherService) + .to receive(:execute) + + worker.perform(group.id) + end + + it 'deletes namespace aggregated schedule row' do + worker.perform(group.id) + + expect(group.reload.aggregation_schedule).to be_nil + end + + context 'when something goes wrong when updating' do + before do + allow_any_instance_of(Namespaces::StatisticsRefresherService) + .to receive(:execute) + .and_raise(Namespaces::StatisticsRefresherService::RefresherError, 'error') + end + + it 'does not delete the aggregation schedule' do + worker.perform(group.id) + + expect(group.reload.aggregation_schedule).to be_present + end + + it 'logs the error' do + # A Namespace::RootStatisticsWorker is scheduled when + # a Namespace::AggregationSchedule is created, so having + # create(:group, :with_aggregation_schedule), will execute + # another worker + allow_any_instance_of(Namespace::AggregationSchedule) + .to receive(:schedule_root_storage_statistics).and_return(nil) + + expect(Gitlab::SidekiqLogger).to receive(:error).once + + worker.perform(group.id) + end + end + end + + context 'with no namespace' do + before do + group.destroy + end + + it 'does not execute the refresher service' do + expect_any_instance_of(Namespaces::StatisticsRefresherService) + .not_to receive(:execute) + + worker.perform(group.id) + end + end + + context 'with a namespace with no aggregation scheduled' do + before do + group.aggregation_schedule.destroy + end + + it 'does not execute the refresher service' do + expect_any_instance_of(Namespaces::StatisticsRefresherService) + .not_to receive(:execute) + + worker.perform(group.id) + end + end + + context 'when update_statistics_namespace is off' do + it 'does not create a new one' do + stub_feature_flags(update_statistics_namespace: false, namespace: group) + + expect_any_instance_of(Namespaces::StatisticsRefresherService) + .not_to receive(:execute) + + worker.perform(group.id) + end + end +end diff --git a/spec/workers/namespaces/schedule_aggregation_worker_spec.rb b/spec/workers/namespaces/schedule_aggregation_worker_spec.rb new file mode 100644 index 00000000000..7432ca12f2a --- /dev/null +++ b/spec/workers/namespaces/schedule_aggregation_worker_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Namespaces::ScheduleAggregationWorker, '#perform' do + let(:group) { create(:group) } + + subject(:worker) { described_class.new } + + context 'when group is the root ancestor' do + context 'when aggregation schedule exists' do + it 'does not create a new one' do + Namespace::AggregationSchedule.safe_find_or_create_by!(namespace_id: group.id) + + expect do + worker.perform(group.id) + end.not_to change(Namespace::AggregationSchedule, :count) + end + end + + context 'when update_statistics_namespace is off' do + it 'does not create a new one' do + stub_feature_flags(update_statistics_namespace: false, namespace: group) + + expect do + worker.perform(group.id) + end.not_to change(Namespace::AggregationSchedule, :count) + end + end + + context 'when aggregation schedule does not exist' do + it 'creates one' do + allow_any_instance_of(Namespace::AggregationSchedule) + .to receive(:schedule_root_storage_statistics).and_return(nil) + + expect do + worker.perform(group.id) + end.to change(Namespace::AggregationSchedule, :count).by(1) + + expect(group.aggregation_schedule).to be_present + end + end + end + + context 'when group is not the root ancestor' do + let(:parent_group) { create(:group) } + let(:group) { create(:group, parent: parent_group) } + + it 'creates an aggregation schedule for the root' do + allow_any_instance_of(Namespace::AggregationSchedule) + .to receive(:schedule_root_storage_statistics).and_return(nil) + + worker.perform(group.id) + + expect(parent_group.aggregation_schedule).to be_present + end + end + + context 'when namespace does not exist' do + it 'logs the error' do + expect(Gitlab::SidekiqLogger).to receive(:error).once + + worker.perform(12345) + end + end +end |