Commit e75d9437 authored by Patrick Bajao's avatar Patrick Bajao

Merge branch 'lm-improve-cancelable-pending-pipelines-query' into 'master'

Splits up auto_cancelable_pipelines query and adds limit for pipelines

See merge request gitlab-org/gitlab!68585
parents 6ec9933f ad64acb2
......@@ -308,6 +308,7 @@ module Ci
scope :ci_and_parent_sources, -> { where(source: Enums::Ci::Pipeline.ci_and_parent_sources.values) }
scope :for_user, -> (user) { where(user: user) }
scope :for_sha, -> (sha) { where(sha: sha) }
scope :where_not_sha, -> (sha) { where.not(sha: sha) }
scope :for_source_sha, -> (source_sha) { where(source_sha: source_sha) }
scope :for_sha_or_source_sha, -> (sha) { for_sha(sha).or(for_source_sha(sha)) }
scope :for_ref, -> (ref) { where(ref: ref) }
......
......@@ -7,15 +7,19 @@ module Gitlab
class CancelPendingPipelines < Chain::Base
include Chain::Helpers
BATCH_SIZE = 25
# rubocop: disable CodeReuse/ActiveRecord
def perform!
return unless project.auto_cancel_pending_pipelines?
Gitlab::OptimisticLocking.retry_lock(auto_cancelable_pipelines, name: 'cancel_pending_pipelines') do |cancelables|
cancelables.find_each do |cancelable|
cancelable.auto_cancel_running(pipeline)
cancelables.select(:id).each_batch(of: BATCH_SIZE) do |cancelables_batch|
auto_cancel_interruptible_pipelines(cancelables_batch.ids)
end
end
end
# rubocop: enable CodeReuse/ActiveRecord
def break?
false
......@@ -23,16 +27,21 @@ module Gitlab
private
# rubocop: disable CodeReuse/ActiveRecord
def auto_cancelable_pipelines
project.all_pipelines.ci_and_parent_sources
.where(ref: pipeline.ref)
.where.not(id: pipeline.same_family_pipeline_ids)
.where.not(sha: project.commit(pipeline.ref).try(:id))
project.all_pipelines.created_after(1.week.ago)
.ci_and_parent_sources
.for_ref(pipeline.ref)
.id_not_in(pipeline.same_family_pipeline_ids)
.where_not_sha(project.commit(pipeline.ref).try(:id))
.alive_or_scheduled
end
def auto_cancel_interruptible_pipelines(pipeline_ids)
::Ci::Pipeline
.id_in(pipeline_ids)
.with_only_interruptible_builds
.each { |cancelable| cancelable.auto_cancel_running(pipeline) }
end
# rubocop: enable CodeReuse/ActiveRecord
end
end
end
......
......@@ -44,6 +44,14 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::CancelPendingPipelines do
expect(build_statuses(pipeline)).to contain_exactly('pending')
end
it 'cancels the builds with 2 queries to avoid query timeout' do
second_query_regex = /WHERE "ci_pipelines"\."id" = \d+ AND \(NOT EXISTS/
recorder = ActiveRecord::QueryRecorder.new { perform }
second_query = recorder.occurrences.keys.filter { |occ| occ =~ second_query_regex }
expect(second_query).to be_one
end
context 'when the previous pipeline has a child pipeline' do
let(:child_pipeline) { create(:ci_pipeline, child_of: prev_pipeline) }
......
......@@ -183,6 +183,28 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
end
end
describe '.where_not_sha' do
let_it_be(:pipeline) { create(:ci_pipeline, sha: 'abcx') }
let_it_be(:pipeline_2) { create(:ci_pipeline, sha: 'abc') }
let(:sha) { 'abc' }
subject { described_class.where_not_sha(sha) }
it 'returns the pipeline without the specified sha' do
is_expected.to contain_exactly(pipeline)
end
context 'when argument is array' do
let(:sha) { %w[abc abcx] }
it 'returns the pipelines without the specified shas' do
pipeline_3 = create(:ci_pipeline, sha: 'abcy')
is_expected.to contain_exactly(pipeline_3)
end
end
end
describe '.for_source_sha' do
subject { described_class.for_source_sha(source_sha) }
......
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