Remove logic keeping sharding_key_id up to date in runners
UPDATE: we might want to keep sharding_key_id
in the form of a owner_project_id
column, only containing values for project runners. We would also want to preserve UpdateProjectRunnersOwnerService
so that orphaned runners are deleted.
As decided in #470872 (comment 2382046293), we'll replace sharding_key_id
by organization_id
. Since we had changed the logic that determines a runner's owner to use sharding_key_id
for performance and flexibility, we've reverted the logic to calculate the owner in #523697 (closed), and once we've made the organization_id
the sharding key for runners, we can remove the logic that keeps sharding_key_id
up to date in runners.
Patch to remove logic keeping sharding_key_id up to date
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb
index 1d4bb4ef4911..f9a848d490ee 100644
--- a/app/models/ci/runner.rb
+++ b/app/models/ci/runner.rb
@@ -381,11 +381,6 @@ def assign_to(project, current_user = nil)
begin
transaction do
- if projects.id_in(sharding_key_id).empty? && !update_project_id
- self.errors.add(:assign_to, 'Runner is orphaned and no fallback owner exists')
- next false
- end
-
self.runner_projects << ::Ci::RunnerProject.new(project: project, runner: self)
self.save!
end
@@ -588,28 +583,6 @@ def partition_id
joins(:runner_managers).merge(RunnerManager.with_upgrade_status(upgrade_status))
end
- def fallback_owner_project
- # NOTE: when a project is deleted, the respective ci_runner_projects records are not immediately
- # deleted by the LFK, so we might find join records that point to a still-existing project
- project_ids = runner_projects.order(:id).pluck(:project_id)
- projects_added_to_runner_asc = Arel.sql("array_position(ARRAY[#{project_ids.join(',')}]::bigint[], id)")
- Project.order(projects_added_to_runner_asc).find_by_id(project_ids)
- end
-
- # Ensure we have a valid sharding_key_id. Logic is similar to the one used in
- # Ci::Runners::UpdateProjectRunnersOwnerService when a project is deleted
- def update_project_id
- project_id = fallback_owner_project&.id
-
- return if project_id.nil?
-
- self.clear_memoization(:owner)
- self.sharding_key_id = project_id
-
- runner_managers.where(runner_type: :project_type).each_batch { |batch| batch.update_all(sharding_key_id: project_id) }
- taggings.where(runner_type: :project_type).update_all(sharding_key_id: project_id)
- end
-
def compute_token_expiration_instance
return unless expiration_interval = Gitlab::CurrentSettings.runner_token_expiration_interval
diff --git a/app/services/ci/runners/update_project_runners_owner_service.rb b/app/services/ci/runners/update_project_runners_owner_service.rb
deleted file mode 100644
index 5b312245f1ff..000000000000
--- a/app/services/ci/runners/update_project_runners_owner_service.rb
+++ /dev/null
@@ -1,67 +0,0 @@
-# frozen_string_literal: true
-
-module Ci
- module Runners
- # Service used to recompute runner owners after a project is deleted.
- class UpdateProjectRunnersOwnerService
- BATCH_SIZE = 1000
-
- # @param [Int] project_id: the ID of the deleted project
- def initialize(project_id)
- @project_id = project_id
- end
-
- def execute
- # Since the project was deleted in the 'main' database, let's ensure that the respective
- # ci_runner_projects join records are also gone (would be handled by LFK otherwise,
- # but it is a helpful precondition for the service's logic)
- Ci::RunnerProject.belonging_to_project(project_id).each_batch do |batch|
- batch.delete_all
- end
-
- # rubocop: disable CodeReuse/ActiveRecord -- this query is too specific to generalize on the models
- runner_projects =
- Ci::RunnerProject.where(Ci::RunnerProject.arel_table[:runner_id].eq(Ci::Runner.arel_table[:id]))
- orphaned_runners = Ci::Runner.project_type.with_sharding_key(project_id)
-
- orphaned_runners.select(:id).each_batch(of: BATCH_SIZE) do |batch|
- runners_missing_owner_project = Ci::Runner.id_in(batch.limit(BATCH_SIZE).pluck_primary_key)
- runners_with_fallback_owner = runners_missing_owner_project.where_exists(runner_projects.limit(1))
-
- Ci::Runner.transaction do
- runner_ids = runners_with_fallback_owner.limit(BATCH_SIZE).pluck_primary_key
-
- runners_with_fallback_owner.update_all(runner_id_update_query(Ci::Runner.arel_table[:id]))
- Ci::RunnerManager.project_type.for_runner(runner_ids)
- .update_all(runner_id_update_query(Ci::RunnerManager.arel_table[:runner_id]))
- Ci::RunnerTagging.project_type.for_runner(runner_ids)
- .update_all(runner_id_update_query(Ci::RunnerTagging.arel_table[:runner_id]))
-
- # Delete any orphaned runners that are still pointing to the project
- # (they are the ones which no longer have any matching ci_runner_projects records)
- # We can afford to sidestep Ci::Runner hooks since we know by definition that
- # there are no Ci::RunnerProject models pointing to these runners (it's the reason they are being deleted)
- runners_missing_owner_project.project_type.with_sharding_key(project_id).delete_all
- end
- end
- # rubocop: enable CodeReuse/ActiveRecord
-
- ServiceResponse.success
- end
-
- private
-
- attr_reader :project_id
-
- def runner_id_update_query(runner_id_column)
- # rubocop: disable CodeReuse/ActiveRecord -- this query is too specific to generalize on the models
- runner_projects = Ci::RunnerProject.where(Ci::RunnerProject.arel_table[:runner_id].eq(runner_id_column))
-
- <<~SQL
- sharding_key_id = (#{runner_projects.order(id: :asc).limit(1).select(:project_id).to_sql})
- SQL
- # rubocop: enable CodeReuse/ActiveRecord
- end
- end
- end
-end
diff --git a/app/workers/ci/runners/update_project_runners_owner_worker.rb b/app/workers/ci/runners/update_project_runners_owner_worker.rb
index 2560af1d6569..c659a54b1e0e 100644
--- a/app/workers/ci/runners/update_project_runners_owner_worker.rb
+++ b/app/workers/ci/runners/update_project_runners_owner_worker.rb
@@ -11,9 +11,7 @@ class UpdateProjectRunnersOwnerWorker
feature_category :runner
- def handle_event(event)
- ::Ci::Runners::UpdateProjectRunnersOwnerService.new(event.data[:project_id]).execute
- end
+ def handle_event(event); end
end
end
end
diff --git a/lib/gitlab/event_store.rb b/lib/gitlab/event_store.rb
index 75070c56a065..7a6dbbd7a73a 100644
--- a/lib/gitlab/event_store.rb
+++ b/lib/gitlab/event_store.rb
@@ -42,7 +42,6 @@ def configure!(store)
store.subscribe ::MergeRequests::UpdateHeadPipelineWorker, to: ::Ci::PipelineCreatedEvent
store.subscribe ::Namespaces::UpdateRootStatisticsWorker, to: ::Projects::ProjectDeletedEvent
- store.subscribe ::Ci::Runners::UpdateProjectRunnersOwnerWorker, to: ::Projects::ProjectDeletedEvent
store.subscribe ::MergeRequests::ProcessAutoMergeFromEventWorker, to: ::MergeRequests::DraftStateChangeEvent
store.subscribe ::MergeRequests::ProcessAutoMergeFromEventWorker, to: ::MergeRequests::DiscussionsResolvedEvent
diff --git a/spec/services/ci/runners/update_project_runners_owner_service_spec.rb b/spec/services/ci/runners/update_project_runners_owner_service_spec.rb
deleted file mode 100644
index 6dfd98cf850b..000000000000
--- a/spec/services/ci/runners/update_project_runners_owner_service_spec.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe ::Ci::Runners::UpdateProjectRunnersOwnerService, '#execute', feature_category: :runner do
- let_it_be(:owner_group) { create(:group) }
- let_it_be(:owner_project) { create(:project, group: owner_group) }
- let_it_be(:new_projects) { create_list(:project, 2) }
-
- let_it_be(:owned_runner1) do
- create(:ci_runner, :project, projects: [owner_project, new_projects.first], tag_list: %w[tag1])
- end
-
- let_it_be(:owned_runner2) { create(:ci_runner, :project, projects: [owner_project], tag_list: %w[tag1 tag2]) }
- let_it_be(:owned_runner3) do
- create(:ci_runner, :project, projects: [owner_project, *new_projects.reverse], tag_list: %w[tag2])
- end
-
- let_it_be(:owned_runner4) do
- create(:ci_runner, :project, projects: [owner_project, *new_projects], tag_list: %w[tag1 tag2])
- end
-
- let_it_be(:other_runner) { create(:ci_runner, :project, projects: new_projects, tag_list: %w[tag1 tag2]) }
- let_it_be(:orphaned_runner) { create(:ci_runner, :project, :without_projects, tag_list: %w[tag1 tag2]) }
-
- let_it_be(:owned_runner1_manager) { create(:ci_runner_machine, runner: owned_runner1) }
- let_it_be(:owned_runner2_manager) { create(:ci_runner_machine, runner: owned_runner2) }
- let_it_be(:owned_runner3_manager) { create(:ci_runner_machine, runner: owned_runner3) }
- let_it_be(:owned_runner4_manager) { create(:ci_runner_machine, runner: owned_runner4) }
-
- let(:service) { described_class.new(owner_project.id) }
-
- subject(:execute) { service.execute }
-
- before_all do
- owner_project.destroy!
- end
-
- before do
- stub_const("#{described_class}::BATCH_SIZE", 2)
- end
-
- it 'updates sharding_key_id on affected runners', :aggregate_failures do
- expect { execute }
- # owned_runner1's owner project was deleted
- .to change { owned_runner1.reload.sharding_key_id }.from(owner_project.id).to(new_projects.first.id)
- .and change { owned_runner1_manager.reload.sharding_key_id }.from(owner_project.id).to(new_projects.first.id)
- .and change { tagging_sharding_key_id_for_runner(owned_runner1) }.from(owner_project.id).to(new_projects.first.id)
- # owned_runner2's owner project was deleted and there were no other associated projects to fall back to
- .and change { Ci::Runner.find_by_id(owned_runner2) }.to(nil) # delete, since no other project to adopt it
- .and change { Ci::RunnerManager.find_by_id(owned_runner2_manager) }.to(nil)
- .and change { Ci::RunnerTagging.find_by_runner_id(owned_runner2) }.to(nil)
- # owned_runner3's owner project was deleted
- .and change { owned_runner3.reload.sharding_key_id }.from(owner_project.id).to(new_projects.last.id)
- .and change { owned_runner3_manager.reload.sharding_key_id }.from(owner_project.id).to(new_projects.last.id)
- .and change { tagging_sharding_key_id_for_runner(owned_runner3) }.from(owner_project.id).to(new_projects.last.id)
- # owned_runner4's owner project was deleted
- .and change { owned_runner4.reload.sharding_key_id }.from(owner_project.id).to(new_projects.first.id)
- .and change { owned_runner4_manager.reload.sharding_key_id }.from(owner_project.id).to(new_projects.first.id)
- .and change { tagging_sharding_key_id_for_runner(owned_runner4) }.from(owner_project.id).to(new_projects.first.id)
- # runners whose owner project was not affected
- .and not_change { other_runner.reload.sharding_key_id }.from(new_projects.first.id)
- .and not_change { orphaned_runner.reload.sharding_key_id }
- .and not_change { tagging_sharding_key_id_for_runner(orphaned_runner) }
-
- expect(execute).to be_success
- end
-
- private
-
- def tagging_sharding_key_id_for_runner(runner)
- runner.taggings.pluck(:sharding_key_id).uniq.sole
- end
-end
diff --git a/spec/workers/ci/runners/update_project_runners_owner_worker_spec.rb b/spec/workers/ci/runners/update_project_runners_owner_worker_spec.rb
index cf9e2c93368f..d9726b0956a7 100644
--- a/spec/workers/ci/runners/update_project_runners_owner_worker_spec.rb
+++ b/spec/workers/ci/runners/update_project_runners_owner_worker_spec.rb
@@ -10,15 +10,7 @@
{ project_id: project.id, namespace_id: project.namespace_id, root_namespace_id: project.root_namespace.id }
end
- it_behaves_like 'subscribes to event' do
+ it_behaves_like 'ignores the published event' do
let(:event) { project_deleted_event }
end
-
- it 'calls Ci::Runners::UpdateProjectRunnersOwnerService' do
- expect_next_instance_of(Ci::Runners::UpdateProjectRunnersOwnerService, project.id) do |service|
- expect(service).to receive(:execute)
- end
-
- described_class.new.handle_event(project_deleted_event)
- end
end
Edited by 🤖 GitLab Bot 🤖