Commit 13e7bb61 authored by Kamil Trzciński's avatar Kamil Trzciński

Merge branch 'feature/gb/improve-builds-queueing' into 'master'

Improve queueing and locking of builds exposed to runners [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!54579
parents d2f630f7 c5e3e441
...@@ -10,6 +10,8 @@ module Ci ...@@ -10,6 +10,8 @@ module Ci
Result = Struct.new(:build, :build_json, :valid?) Result = Struct.new(:build, :build_json, :valid?)
MAX_QUEUE_DEPTH = 50
def initialize(runner) def initialize(runner)
@runner = runner @runner = runner
@metrics = ::Gitlab::Ci::Queue::Metrics.new(runner) @metrics = ::Gitlab::Ci::Queue::Metrics.new(runner)
...@@ -33,6 +35,14 @@ module Ci ...@@ -33,6 +35,14 @@ module Ci
depth += 1 depth += 1
@metrics.increment_queue_operation(:queue_iteration) @metrics.increment_queue_operation(:queue_iteration)
if depth > max_queue_depth
@metrics.increment_queue_operation(:queue_depth_limit)
valid = false
break
end
# We read builds from replicas # We read builds from replicas
# It is likely that some other concurrent connection is processing # It is likely that some other concurrent connection is processing
# a given build at a given moment. To avoid an expensive compute # a given build at a given moment. To avoid an expensive compute
...@@ -44,6 +54,7 @@ module Ci ...@@ -44,6 +54,7 @@ module Ci
# - our queue is not complete as some resources are locked temporarily # - our queue is not complete as some resources are locked temporarily
# - we need to re-process it again to ensure that all builds are handled # - we need to re-process it again to ensure that all builds are handled
valid = false valid = false
next next
end end
...@@ -158,6 +169,16 @@ module Ci ...@@ -158,6 +169,16 @@ module Ci
nil nil
end end
def max_queue_depth
@max_queue_depth ||= begin
if Feature.enabled?(:gitlab_ci_builds_queue_limit, runner, default_enabled: false)
MAX_QUEUE_DEPTH
else
::Gitlab::Database::MAX_INT_VALUE
end
end
end
# Force variables evaluation to occur now # Force variables evaluation to occur now
def present_build!(build) def present_build!(build)
# We need to use the presenter here because Gitaly calls in the presenter # We need to use the presenter here because Gitaly calls in the presenter
......
---
title: Improve performance of builds queuing by introducing a limit on the queue depth
merge_request: 54579
author:
type: performance
---
name: gitlab_ci_builds_queue_limit
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/54579
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/323201
milestone: '13.10'
type: development
group: group::continuous integration
default_enabled: false
...@@ -27,6 +27,7 @@ module Gitlab ...@@ -27,6 +27,7 @@ module Gitlab
:queue_attempt, :queue_attempt,
:queue_conflict, :queue_conflict,
:queue_iteration, :queue_iteration,
:queue_depth_limit,
:queue_replication_lag, :queue_replication_lag,
:runner_pre_assign_checks_failed, :runner_pre_assign_checks_failed,
:runner_pre_assign_checks_success, :runner_pre_assign_checks_success,
......
...@@ -790,6 +790,46 @@ module Ci ...@@ -790,6 +790,46 @@ module Ci
end end
end end
context 'when max queue depth is reached' do
let!(:pending_job) { create(:ci_build, :pending, :degenerated, pipeline: pipeline) }
let!(:pending_job_2) { create(:ci_build, :pending, :degenerated, pipeline: pipeline) }
let!(:pending_job_3) { create(:ci_build, :pending, pipeline: pipeline) }
before do
stub_const("#{described_class}::MAX_QUEUE_DEPTH", 2)
end
context 'when feature is enabled' do
before do
stub_feature_flags(gitlab_ci_builds_queue_limit: true)
end
it 'returns 409 conflict' do
expect(Ci::Build.pending.unstarted.count).to eq 3
result = described_class.new(specific_runner).execute
expect(result).not_to be_valid
expect(result.build).to be_nil
end
end
context 'when feature is disabled' do
before do
stub_feature_flags(gitlab_ci_builds_queue_limit: false)
end
it 'returns a valid result' do
expect(Ci::Build.pending.unstarted.count).to eq 3
result = described_class.new(specific_runner).execute
expect(result).to be_valid
expect(result.build).to eq pending_job_3
end
end
end
def execute(runner, params = {}) def execute(runner, params = {})
described_class.new(runner).execute(params).build described_class.new(runner).execute(params).build
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