diff options
author | Dylan Griffith <dyl.griffith@gmail.com> | 2018-04-30 09:39:47 +0400 |
---|---|---|
committer | Dylan Griffith <dyl.griffith@gmail.com> | 2018-04-30 10:02:25 +0400 |
commit | 87740df2ba7153439c30544f299b235632717738 (patch) | |
tree | 66c40d2cf0e4289991ee8f3a9d038ac400f29da9 | |
parent | 0077679ae88793b200bdcf69d2ca7e4d15e6f7fa (diff) | |
download | gitlab-ce-87740df2ba7153439c30544f299b235632717738.tar.gz |
Revert fair scheduling for all builds
Per discussion in https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9646#note_65730532 this logic is being optimized elsewhere and it will simplify things if we make less changes to this code right now.
-rw-r--r-- | app/models/ci/runner.rb | 18 | ||||
-rw-r--r-- | app/services/ci/register_job_service.rb | 47 | ||||
-rw-r--r-- | spec/models/ci/runner_spec.rb | 67 | ||||
-rw-r--r-- | spec/services/ci/register_job_service_spec.rb | 51 |
4 files changed, 43 insertions, 140 deletions
diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index 6904aca5e68..40d828b8414 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -99,24 +99,6 @@ module Ci self.token = SecureRandom.hex(15) if self.token.blank? end - def accessible_projects - accessible_projects = - if shared? - Project.with_shared_runners - elsif project? - projects - elsif group? - hierarchy_groups = Gitlab::GroupHierarchy.new(groups).base_and_descendants - Project.where(namespace_id: hierarchy_groups) - else - Project.none - end - - accessible_projects - .with_builds_enabled - .without_deleted - end - def assign_to(project, current_user = nil) self.is_shared = false if shared? self.save diff --git a/app/services/ci/register_job_service.rb b/app/services/ci/register_job_service.rb index 64549ea3ce2..55d0273847c 100644 --- a/app/services/ci/register_job_service.rb +++ b/app/services/ci/register_job_service.rb @@ -14,7 +14,14 @@ module Ci end def execute - builds = builds_for_runner + builds = + if runner.shared? + builds_for_shared_runner + elsif runner.group? + builds_for_group_runner + else + builds_for_project_runner + end valid = true @@ -63,27 +70,39 @@ module Ci private - def builds_for_runner - new_builds - .joins("LEFT JOIN (#{running_projects.to_sql}) AS running_projects ON ci_builds.project_id=running_projects.project_id") - .order('COALESCE(running_projects.running_builds, 0) ASC', 'ci_builds.id ASC') + def builds_for_shared_runner + new_builds. + # don't run projects which have not enabled shared runners and builds + joins(:project).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'). + + # 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 + joins("LEFT JOIN (#{running_builds_for_shared_runners.to_sql}) AS project_builds ON ci_builds.project_id=project_builds.project_id") + .order('COALESCE(project_builds.running_builds, 0) ASC', 'ci_builds.id ASC') end - # New builds from the accessible projects - def new_builds - filter_builds(Ci::Build.pending.unstarted) + def builds_for_project_runner + new_builds.where(project: runner.projects.without_deleted.with_builds_enabled).order('created_at ASC') end - # Count running builds from the accessible projects - def running_projects - filter_builds(Ci::Build.running) + def builds_for_group_runner + hierarchy_groups = Gitlab::GroupHierarchy.new(runner.groups).base_and_descendants + projects = Project.where(namespace_id: hierarchy_groups).without_deleted.with_builds_enabled + new_builds.where(project: projects.without_deleted.with_builds_enabled).order('created_at ASC') + end + + def running_builds_for_shared_runners + Ci::Build.running.where(runner: Ci::Runner.shared) .group(:project_id).select(:project_id, 'count(*) AS running_builds') end - # Filter the builds from the accessible projects - def filter_builds(builds) + def new_builds + builds = Ci::Build.pending.unstarted builds = builds.ref_protected if runner.ref_protected? - builds.where(project: runner.accessible_projects) + builds end def register_failure diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index fbf9539e698..d6ce97a9b28 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -792,73 +792,6 @@ describe Ci::Runner do end end - describe '#accessible_projects' do - let!(:shared_runner) { create(:ci_runner, :shared) } - let!(:shared_project) { create(:project, shared_runners_enabled: true) } - - let!(:project_runner) { create(:ci_runner) } - let!(:project_project) { create(:project, runners: [project_runner], shared_runners_enabled: false) } - - let!(:group_runner) { create(:ci_runner) } - - let!(:parent_group) { create(:group) } - let!(:parent_group_project) do - create(:project, group: parent_group, shared_runners_enabled: false) - end - - let!(:group) { create :group, runners: [group_runner], parent: parent_group } - let!(:group_project) do - create(:project, group: group, shared_runners_enabled: false) - end - - let!(:nested_group_project) do - nested_group = create :group, parent: group - create(:project, group: nested_group, shared_runners_enabled: false) - end - - it 'returns the project with a shared runner' do - expect(shared_runner.reload.accessible_projects).to eq [shared_project] - end - - it 'returns the project with a project runner' do - expect(project_runner.reload.accessible_projects).to eq [project_project] - end - - it 'returns the projects with a group and nested group runner', :nested_groups do - expect(group_runner.reload.accessible_projects).to eq [group_project, nested_group_project] - end - - context 'deleted' do - before do - shared_project.update_attributes!(pending_delete: true) - project_project.update_attributes!(pending_delete: true) - group_project.update_attributes!(pending_delete: true) - nested_group_project.update_attributes!(pending_delete: true) - end - - it 'returns no projects' do - expect(shared_runner.reload.accessible_projects).to be_empty - expect(project_runner.reload.accessible_projects).to be_empty - expect(group_runner.reload.accessible_projects).to be_empty - end - end - - context 'builds disabled' do - before do - shared_project.update_attributes!(builds_enabled: false) - project_project.update_attributes!(builds_enabled: false) - group_project.update_attributes!(builds_enabled: false) - nested_group_project.update_attributes!(builds_enabled: false) - end - - it 'returns no projects' do - expect(shared_runner.reload.accessible_projects).to be_empty - expect(project_runner.reload.accessible_projects).to be_empty - expect(group_runner.reload.accessible_projects).to be_empty - end - end - end - describe '#invalidate_build_cache!' do context 'runner can pick the build' do it 'calls #tick_runner_queue' do diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb index 0c343425392..7d3c43eeaf7 100644 --- a/spec/services/ci/register_job_service_spec.rb +++ b/spec/services/ci/register_job_service_spec.rb @@ -195,56 +195,25 @@ module Ci let!(:unrelated_group_runner) { create :ci_runner, groups: [unrelated_group] } it 'does not consider builds from other group runners' do - expect(described_class.new(group_runner).send(:builds_for_runner).count).to eq 6 + expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 6 execute(group_runner) - expect(described_class.new(group_runner).send(:builds_for_runner).count).to eq 5 + expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 5 execute(group_runner) - expect(described_class.new(group_runner).send(:builds_for_runner).count).to eq 4 + expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 4 execute(group_runner) - expect(described_class.new(group_runner).send(:builds_for_runner).count).to eq 3 + expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 3 execute(group_runner) - expect(described_class.new(group_runner).send(:builds_for_runner).count).to eq 2 + expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 2 execute(group_runner) - expect(described_class.new(group_runner).send(:builds_for_runner).count).to eq 1 + expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 1 execute(group_runner) - expect(described_class.new(group_runner).send(:builds_for_runner).count).to eq 0 - expect(execute(group_runner)).to be_nil - end - - it 'prefers projects without builds first' do - # it gets for one build from each of the projects - expect(execute(group_runner)).to eq(build1_project1) - expect(execute(group_runner)).to eq(build1_project2) - expect(execute(group_runner)).to eq(build1_project3) - - # then it gets a second build from each of the projects - expect(execute(group_runner)).to eq(build2_project1) - expect(execute(group_runner)).to eq(build2_project2) - - # in the end the third build - expect(execute(group_runner)).to eq(build3_project1) - - expect(execute(group_runner)).to be_nil - end - - it 'equalises number of running builds' do - # after finishing the first build for project 1, get a second build from the same project - expect(execute(group_runner)).to eq(build1_project1) - build1_project1.reload.success - expect(execute(group_runner)).to eq(build2_project1) - - expect(execute(group_runner)).to eq(build1_project2) - build1_project2.reload.success - expect(execute(group_runner)).to eq(build2_project2) - expect(execute(group_runner)).to eq(build1_project3) - expect(execute(group_runner)).to eq(build3_project1) - + expect(described_class.new(group_runner).send(:builds_for_group_runner).count).to eq 0 expect(execute(group_runner)).to be_nil end end @@ -282,7 +251,7 @@ module Ci let!(:other_build) { create :ci_build, pipeline: pipeline } before do - allow_any_instance_of(Ci::RegisterJobService).to receive(:builds_for_runner) + allow_any_instance_of(Ci::RegisterJobService).to receive(:builds_for_project_runner) .and_return(Ci::Build.where(id: [pending_job, other_build])) end @@ -294,7 +263,7 @@ module Ci context 'when single build is in queue' do before do - allow_any_instance_of(Ci::RegisterJobService).to receive(:builds_for_runner) + allow_any_instance_of(Ci::RegisterJobService).to receive(:builds_for_project_runner) .and_return(Ci::Build.where(id: pending_job)) end @@ -305,7 +274,7 @@ module Ci context 'when there is no build in queue' do before do - allow_any_instance_of(Ci::RegisterJobService).to receive(:builds_for_runner) + allow_any_instance_of(Ci::RegisterJobService).to receive(:builds_for_project_runner) .and_return(Ci::Build.none) end |