Commit f89dc4b0 authored by Stan Hu's avatar Stan Hu

Optimize page loading of Admin::RunnersController#show

This commit optimizes the page loading of this page in several ways:

1. Remove exact counting of projects on the page. By default, a `SELECT
COUNT(*) FROM projects` would be called, which could take seconds on an
instance with many projects.

2. Preload project/namespace/routes where necessary. This reduces a
significant number of N+1 queries.

3. Remove the use of `becomes(Namespace)` because this causes a SQL
query each time it is called. Instead, use the Rails path helpers to
generate the path directly via `project.namespace`.

Closes https://gitlab.com/gitlab-org/gitlab/issues/119093
parent 3e4835ab
......@@ -66,7 +66,7 @@ class Admin::RunnersController < Admin::ApplicationController
# rubocop: disable CodeReuse/ActiveRecord
def assign_builds_and_projects
@builds = runner.builds.order('id DESC').first(30)
@builds = runner.builds.order('id DESC').preload_project_and_pipeline_project.first(30)
@projects =
if params[:search].present?
::Project.search(params[:search])
......@@ -75,7 +75,8 @@ class Admin::RunnersController < Admin::ApplicationController
end
@projects = @projects.where.not(id: runner.projects.select(:id)) if runner.projects.any?
@projects = @projects.page(params[:page]).per(30)
@projects = @projects.inc_routes
@projects = @projects.page(params[:page]).per(30).without_count
end
# rubocop: enable CodeReuse/ActiveRecord
end
......@@ -172,6 +172,9 @@ module Ci
scope :queued_before, ->(time) { where(arel_table[:queued_at].lt(time)) }
scope :order_id_desc, -> { order('ci_builds.id DESC') }
PROJECT_ROUTE_AND_NAMESPACE_ROUTE = { project: [:project_feature, :route, { namespace: :route }] }.freeze
scope :preload_project_and_pipeline_project, -> { preload(PROJECT_ROUTE_AND_NAMESPACE_ROUTE, pipeline: PROJECT_ROUTE_AND_NAMESPACE_ROUTE) }
acts_as_taggable
add_authentication_token_field :token, encrypted: :optional
......
......@@ -48,7 +48,7 @@
= project.full_name
%td
.float-right
= link_to 'Disable', [:admin, project.namespace.becomes(Namespace), project, runner_project], method: :delete, class: 'btn btn-danger btn-sm'
= link_to 'Disable', admin_namespace_project_runner_project_path(project.namespace, project, runner_project), method: :delete, class: 'btn btn-danger btn-sm'
%table.table.unassigned-projects
%thead
......@@ -70,10 +70,10 @@
= project.full_name
%td
.float-right
= form_for [:admin, project.namespace.becomes(Namespace), project, project.runner_projects.new] do |f|
= form_for project.runner_projects.new, url: admin_namespace_project_runner_projects_path(project.namespace, project), method: :post do |f|
= f.hidden_field :runner_id, value: @runner.id
= f.submit 'Enable', class: 'btn btn-sm'
= paginate @projects, theme: "gitlab"
= paginate_without_count @projects
.col-md-6
%h4 Recent jobs served by this Runner
......
---
title: Optimize page loading of Admin::RunnersController#show
merge_request: 23309
author:
type: performance
......@@ -3,7 +3,7 @@
require 'spec_helper'
describe Admin::RunnersController do
let!(:runner) { create(:ci_runner) }
let_it_be(:runner) { create(:ci_runner) }
before do
sign_in(create(:admin))
......@@ -36,6 +36,16 @@ describe Admin::RunnersController do
end
describe '#show' do
render_views
let_it_be(:project) { create(:project) }
let_it_be(:project_two) { create(:project) }
before_all do
create(:ci_build, runner: runner, project: project)
create(:ci_build, runner: runner, project: project_two)
end
it 'shows a particular runner' do
get :show, params: { id: runner.id }
......@@ -47,6 +57,21 @@ describe Admin::RunnersController do
expect(response).to have_gitlab_http_status(404)
end
it 'avoids N+1 queries', :request_store do
get :show, params: { id: runner.id }
control_count = ActiveRecord::QueryRecorder.new { get :show, params: { id: runner.id } }.count
new_project = create(:project)
create(:ci_build, runner: runner, project: new_project)
# There is one additional query looking up subject.group in ProjectPolicy for the
# needs_new_sso_session permission
expect { get :show, params: { id: runner.id } }.not_to exceed_query_limit(control_count + 1)
expect(response).to have_gitlab_http_status(200)
end
end
describe '#update' do
......
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