2021-09-30 23:02:18 +05:30
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Ci
|
|
|
|
module Queue
|
|
|
|
class PendingBuildsStrategy
|
|
|
|
attr_reader :runner
|
|
|
|
|
|
|
|
def initialize(runner)
|
|
|
|
@runner = runner
|
|
|
|
end
|
|
|
|
|
|
|
|
# rubocop:disable CodeReuse/ActiveRecord
|
|
|
|
def builds_for_shared_runner
|
2021-10-27 15:23:28 +05:30
|
|
|
shared_builds = builds_available_for_shared_runners
|
2021-09-30 23:02:18 +05:30
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
builds_ordered_for_shared_runners(shared_builds)
|
2021-09-30 23:02:18 +05:30
|
|
|
end
|
|
|
|
|
2021-11-11 11:23:49 +05:30
|
|
|
def builds_for_group_runner
|
|
|
|
return new_builds.none if runner.namespace_ids.empty?
|
|
|
|
|
2022-10-11 01:57:18 +05:30
|
|
|
new_builds_relation = new_builds.where('ci_pending_builds.namespace_traversal_ids && ARRAY[?]::int[]', runner.namespace_ids)
|
|
|
|
|
|
|
|
return order(new_builds_relation) if ::Feature.enabled?(:order_builds_for_group_runner)
|
|
|
|
|
|
|
|
new_builds_relation
|
2021-11-11 11:23:49 +05:30
|
|
|
end
|
|
|
|
|
2021-09-30 23:02:18 +05:30
|
|
|
def builds_matching_tag_ids(relation, ids)
|
2022-08-13 15:12:31 +05:30
|
|
|
relation.for_tags(runner.tags_ids)
|
2021-09-30 23:02:18 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def builds_with_any_tags(relation)
|
2022-08-13 15:12:31 +05:30
|
|
|
relation.where('cardinality(tag_ids) > 0')
|
2021-09-30 23:02:18 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def order(relation)
|
|
|
|
relation.order('build_id ASC')
|
|
|
|
end
|
|
|
|
|
|
|
|
def new_builds
|
|
|
|
::Ci::PendingBuild.all
|
|
|
|
end
|
|
|
|
|
|
|
|
def build_ids(relation)
|
|
|
|
relation.pluck(:build_id)
|
|
|
|
end
|
|
|
|
|
|
|
|
private
|
|
|
|
|
2021-10-27 15:23:28 +05:30
|
|
|
def builds_available_for_shared_runners
|
2022-08-13 15:12:31 +05:30
|
|
|
new_builds.with_instance_runners
|
2021-10-27 15:23:28 +05:30
|
|
|
end
|
|
|
|
|
|
|
|
def builds_ordered_for_shared_runners(relation)
|
2022-07-16 23:28:13 +05:30
|
|
|
if Feature.enabled?(:ci_queueing_disaster_recovery_disable_fair_scheduling, runner, type: :ops)
|
2021-10-27 15:23:28 +05:30
|
|
|
# if disaster recovery is enabled, we fallback to FIFO scheduling
|
|
|
|
relation.order('ci_pending_builds.build_id ASC')
|
|
|
|
else
|
|
|
|
# Implement fair scheduling
|
|
|
|
# this returns builds that are ordered by number of running builds
|
|
|
|
# we prefer projects that don't use shared runners at all
|
|
|
|
relation
|
|
|
|
.with(running_builds_for_shared_runners_cte.to_arel)
|
|
|
|
.joins("LEFT JOIN project_builds ON ci_pending_builds.project_id = project_builds.project_id")
|
|
|
|
.order(Arel.sql('COALESCE(project_builds.running_builds, 0) ASC'), 'ci_pending_builds.build_id ASC')
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-09-30 23:02:18 +05:30
|
|
|
def running_builds_for_shared_runners_cte
|
|
|
|
running_builds = ::Ci::RunningBuild
|
|
|
|
.instance_type
|
|
|
|
.group(:project_id)
|
|
|
|
.select(:project_id, 'COUNT(*) AS running_builds')
|
|
|
|
|
|
|
|
::Gitlab::SQL::CTE
|
|
|
|
.new(:project_builds, running_builds, materialized: true)
|
|
|
|
end
|
|
|
|
# rubocop:enable CodeReuse/ActiveRecord
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2021-10-27 15:23:28 +05:30
|
|
|
|
|
|
|
Ci::Queue::PendingBuildsStrategy.prepend_mod_with('Ci::Queue::PendingBuildsStrategy')
|