67 lines
2.2 KiB
Ruby
67 lines
2.2 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Ci
|
|
module Queue
|
|
class BuildsTableStrategy
|
|
attr_reader :runner
|
|
|
|
def initialize(runner)
|
|
@runner = runner
|
|
end
|
|
|
|
# rubocop:disable CodeReuse/ActiveRecord
|
|
def builds_for_shared_runner
|
|
relation = new_builds
|
|
# don't run projects which have not enabled shared runners and builds
|
|
.joins('INNER JOIN projects ON ci_builds.project_id = projects.id')
|
|
.where(projects: { shared_runners_enabled: true, pending_delete: false })
|
|
.joins('LEFT JOIN project_features ON ci_builds.project_id = project_features.project_id')
|
|
.where('project_features.builds_access_level IS NULL or project_features.builds_access_level > 0')
|
|
|
|
if Feature.enabled?(:ci_queueing_disaster_recovery, runner, type: :ops, default_enabled: :yaml)
|
|
# if disaster recovery is enabled, we fallback to FIFO scheduling
|
|
relation.order('ci_builds.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
|
|
.joins("LEFT JOIN (#{running_builds_for_shared_runners.to_sql}) AS project_builds ON ci_builds.project_id = project_builds.project_id")
|
|
.order(Arel.sql('COALESCE(project_builds.running_builds, 0) ASC'), 'ci_builds.id ASC')
|
|
end
|
|
end
|
|
|
|
def builds_matching_tag_ids(relation, ids)
|
|
# pick builds that does not have other tags than runner's one
|
|
relation.matches_tag_ids(ids)
|
|
end
|
|
|
|
def builds_with_any_tags(relation)
|
|
# pick builds that have at least one tag
|
|
relation.with_any_tags
|
|
end
|
|
|
|
def order(relation)
|
|
relation.order('id ASC')
|
|
end
|
|
|
|
def new_builds
|
|
::Ci::Build.pending.unstarted
|
|
end
|
|
|
|
def build_ids(relation)
|
|
relation.pluck(:id)
|
|
end
|
|
|
|
private
|
|
|
|
def running_builds_for_shared_runners
|
|
::Ci::Build.running
|
|
.where(runner: ::Ci::Runner.instance_type)
|
|
.group(:project_id)
|
|
.select(:project_id, 'COUNT(*) AS running_builds')
|
|
end
|
|
# rubocop:enable CodeReuse/ActiveRecord
|
|
end
|
|
end
|
|
end
|