Commit e4d50f0d authored by David Fernandez's avatar David Fernandez

Merge branch 'mk/speed-up-merge-request-creation-action' into 'master'

Improve merge request creation response time by performing more tasks asynchronously [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!57453
parents c80ffaf8 51b81434
...@@ -6,7 +6,6 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap ...@@ -6,7 +6,6 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
include RendersCommits include RendersCommits
skip_before_action :merge_request skip_before_action :merge_request
before_action :disable_query_limiting, only: [:create]
before_action :authorize_create_merge_request_from! before_action :authorize_create_merge_request_from!
before_action :apply_diff_view_cookie!, only: [:diffs, :diff_for_path] before_action :apply_diff_view_cookie!, only: [:diffs, :diff_for_path]
before_action :build_merge_request, except: [:create] before_action :build_merge_request, except: [:create]
...@@ -133,13 +132,11 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap ...@@ -133,13 +132,11 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/20801')
end
def incr_count_webide_merge_request def incr_count_webide_merge_request
return if params[:nav_source] != 'webide' return if params[:nav_source] != 'webide'
Gitlab::UsageDataCounters::WebIdeCounter.increment_merge_requests_count Gitlab::UsageDataCounters::WebIdeCounter.increment_merge_requests_count
end end
end end
Projects::MergeRequests::CreationsController.prepend_ee_mod
...@@ -24,6 +24,16 @@ module MergeRequests ...@@ -24,6 +24,16 @@ module MergeRequests
merge_request.create_cross_references!(current_user) merge_request.create_cross_references!(current_user)
OnboardingProgressService.new(merge_request.target_project.namespace).execute(action: :merge_request_created) OnboardingProgressService.new(merge_request.target_project.namespace).execute(action: :merge_request_created)
todo_service.new_merge_request(merge_request, current_user)
merge_request.cache_merge_request_closes_issues!(current_user)
Gitlab::UsageDataCounters::MergeRequestCounter.count(:create)
link_lfs_objects(merge_request)
end
def link_lfs_objects(merge_request)
LinkLfsObjectsService.new(merge_request.target_project).execute(merge_request)
end end
end end
end end
......
...@@ -18,12 +18,6 @@ module MergeRequests ...@@ -18,12 +18,6 @@ module MergeRequests
# be performed in Sidekiq # be performed in Sidekiq
NewMergeRequestWorker.perform_async(issuable.id, current_user.id) NewMergeRequestWorker.perform_async(issuable.id, current_user.id)
todo_service.new_merge_request(issuable, current_user)
issuable.cache_merge_request_closes_issues!(current_user)
Gitlab::UsageDataCounters::MergeRequestCounter.count(:create)
link_lfs_objects(issuable)
super super
end end
...@@ -54,10 +48,6 @@ module MergeRequests ...@@ -54,10 +48,6 @@ module MergeRequests
raise Gitlab::Access::AccessDeniedError raise Gitlab::Access::AccessDeniedError
end end
end end
def link_lfs_objects(issuable)
LinkLfsObjectsService.new(issuable.target_project).execute(issuable)
end
end end
end end
......
---
title: Perform more merge request creation tasks asynchronously to improve response
times
merge_request: 57453
author:
type: performance
# frozen_string_literal: true
module EE
module Projects
module MergeRequests
module CreationsController
extend ActiveSupport::Concern
prepended do
before_action :disable_query_limiting, only: [:create]
end
private
def disable_query_limiting
::Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/20801')
end
end
end
end
end
...@@ -139,5 +139,11 @@ RSpec.describe Projects::MergeRequests::CreationsController do ...@@ -139,5 +139,11 @@ RSpec.describe Projects::MergeRequests::CreationsController do
end end
end end
end end
it 'disables query limiting' do
expect(Gitlab::QueryLimiting).to receive(:disable!)
create_merge_request
end
end end
end end
...@@ -93,5 +93,93 @@ RSpec.describe MergeRequests::AfterCreateService do ...@@ -93,5 +93,93 @@ RSpec.describe MergeRequests::AfterCreateService do
expect(merge_request.reload).to be_unchecked expect(merge_request.reload).to be_unchecked
end end
end end
it 'increments the usage data counter of create event' do
counter = Gitlab::UsageDataCounters::MergeRequestCounter
expect { execute_service }.to change { counter.read(:create) }.by(1)
end
context 'todos' do
it 'does not creates todos' do
attributes = {
project: merge_request.target_project,
target_id: merge_request.id,
target_type: merge_request.class.name
}
expect { execute_service }.not_to change { Todo.where(attributes).count }
end
context 'when merge request is assigned to someone' do
let_it_be(:assignee) { create(:user) }
let_it_be(:merge_request) { create(:merge_request, assignees: [assignee]) }
it 'creates a todo for new assignee' do
attributes = {
project: merge_request.target_project,
author: merge_request.author,
user: assignee,
target_id: merge_request.id,
target_type: merge_request.class.name,
action: Todo::ASSIGNED,
state: :pending
}
expect { execute_service }.to change { Todo.where(attributes).count }.by(1)
end
end
context 'when reviewer is assigned' do
let_it_be(:reviewer) { create(:user) }
let_it_be(:merge_request) { create(:merge_request, reviewers: [reviewer]) }
it 'creates a todo for new reviewer' do
attributes = {
project: merge_request.target_project,
author: merge_request.author,
user: reviewer,
target_id: merge_request.id,
target_type: merge_request.class.name,
action: Todo::REVIEW_REQUESTED,
state: :pending
}
expect { execute_service }.to change { Todo.where(attributes).count }.by(1)
end
end
end
context 'when saving references to issues that the created merge request closes' do
let_it_be(:first_issue) { create(:issue, project: merge_request.target_project) }
let_it_be(:second_issue) { create(:issue, project: merge_request.target_project) }
it 'creates a `MergeRequestsClosingIssues` record for each issue' do
merge_request.description = "Closes #{first_issue.to_reference} and #{second_issue.to_reference}"
merge_request.source_branch = "feature"
merge_request.target_branch = merge_request.target_project.default_branch
merge_request.save!
execute_service
issue_ids = MergeRequestsClosingIssues.where(merge_request: merge_request).pluck(:issue_id)
expect(issue_ids).to match_array([first_issue.id, second_issue.id])
end
end
it 'tracks merge request creation in usage data' do
expect(Gitlab::UsageDataCounters::MergeRequestCounter).to receive(:count).with(:create)
execute_service
end
it 'calls MergeRequests::LinkLfsObjectsService#execute' do
service = instance_spy(MergeRequests::LinkLfsObjectsService)
allow(MergeRequests::LinkLfsObjectsService).to receive(:new).with(merge_request.target_project).and_return(service)
execute_service
expect(service).to have_received(:execute).with(merge_request)
end
end end
end end
...@@ -47,16 +47,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do ...@@ -47,16 +47,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do
.to change { project.open_merge_requests_count }.from(0).to(1) .to change { project.open_merge_requests_count }.from(0).to(1)
end end
it 'does not creates todos' do
attributes = {
project: project,
target_id: merge_request.id,
target_type: merge_request.class.name
}
expect(Todo.where(attributes).count).to be_zero
end
it 'creates exactly 1 create MR event', :sidekiq_might_not_need_inline do it 'creates exactly 1 create MR event', :sidekiq_might_not_need_inline do
attributes = { attributes = {
action: :created, action: :created,
...@@ -113,20 +103,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do ...@@ -113,20 +103,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do
end end
it { expect(merge_request.assignees).to eq([user2]) } it { expect(merge_request.assignees).to eq([user2]) }
it 'creates a todo for new assignee' do
attributes = {
project: project,
author: user,
user: user2,
target_id: merge_request.id,
target_type: merge_request.class.name,
action: Todo::ASSIGNED,
state: :pending
}
expect(Todo.where(attributes).count).to eq 1
end
end end
context 'when reviewer is assigned' do context 'when reviewer is assigned' do
...@@ -142,20 +118,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do ...@@ -142,20 +118,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do
it { expect(merge_request.reviewers).to eq([user2]) } it { expect(merge_request.reviewers).to eq([user2]) }
it 'creates a todo for new reviewer' do
attributes = {
project: project,
author: user,
user: user2,
target_id: merge_request.id,
target_type: merge_request.class.name,
action: Todo::REVIEW_REQUESTED,
state: :pending
}
expect(Todo.where(attributes).count).to eq 1
end
it 'invalidates counter cache for reviewers', :use_clean_rails_memory_store_caching do it 'invalidates counter cache for reviewers', :use_clean_rails_memory_store_caching do
expect { merge_request } expect { merge_request }
.to change { user2.review_requested_open_merge_requests_count } .to change { user2.review_requested_open_merge_requests_count }
...@@ -328,12 +290,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do ...@@ -328,12 +290,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do
end end
end end
it 'increments the usage data counter of create event' do
counter = Gitlab::UsageDataCounters::MergeRequestCounter
expect { service.execute }.to change { counter.read(:create) }.by(1)
end
context 'after_save callback to store_mentions' do context 'after_save callback to store_mentions' do
let(:labels) { create_pair(:label, project: project) } let(:labels) { create_pair(:label, project: project) }
let(:milestone) { create(:milestone, project: project) } let(:milestone) { create(:milestone, project: project) }
...@@ -494,35 +450,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do ...@@ -494,35 +450,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do
end end
end end
context 'while saving references to issues that the created merge request closes' do
let(:first_issue) { create(:issue, project: project) }
let(:second_issue) { create(:issue, project: project) }
let(:opts) do
{
title: 'Awesome merge_request',
source_branch: 'feature',
target_branch: 'master',
force_remove_source_branch: '1'
}
end
before do
project.add_maintainer(user)
project.add_developer(user2)
end
it 'creates a `MergeRequestsClosingIssues` record for each issue' do
issue_closing_opts = opts.merge(description: "Closes #{first_issue.to_reference} and #{second_issue.to_reference}")
service = described_class.new(project, user, issue_closing_opts)
allow(service).to receive(:execute_hooks)
merge_request = service.execute
issue_ids = MergeRequestsClosingIssues.where(merge_request: merge_request).pluck(:issue_id)
expect(issue_ids).to match_array([first_issue.id, second_issue.id])
end
end
context 'when source and target projects are different' do context 'when source and target projects are different' do
let(:target_project) { fork_project(project, nil, repository: true) } let(:target_project) { fork_project(project, nil, repository: true) }
...@@ -571,14 +498,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do ...@@ -571,14 +498,6 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do
expect(merge_request).to be_persisted expect(merge_request).to be_persisted
end end
it 'calls MergeRequests::LinkLfsObjectsService#execute', :sidekiq_might_not_need_inline do
expect_next_instance_of(MergeRequests::LinkLfsObjectsService) do |service|
expect(service).to receive(:execute).with(instance_of(MergeRequest))
end
described_class.new(project, user, opts).execute
end
it 'does not create the merge request when the target project is archived' do it 'does not create the merge request when the target project is archived' do
target_project.update!(archived: true) target_project.update!(archived: true)
......
...@@ -948,18 +948,8 @@ RSpec.describe MergeRequests::UpdateService, :mailer do ...@@ -948,18 +948,8 @@ RSpec.describe MergeRequests::UpdateService, :mailer do
end end
it 'removes `MergeRequestsClosingIssues` records when issues are not closed anymore' do it 'removes `MergeRequestsClosingIssues` records when issues are not closed anymore' do
opts = { create(:merge_requests_closing_issues, issue: first_issue, merge_request: merge_request)
title: 'Awesome merge_request', create(:merge_requests_closing_issues, issue: second_issue, merge_request: merge_request)
description: "Closes #{first_issue.to_reference} and #{second_issue.to_reference}",
source_branch: 'feature',
target_branch: 'master',
force_remove_source_branch: '1'
}
merge_request = MergeRequests::CreateService.new(project, user, opts).execute
issue_ids = MergeRequestsClosingIssues.where(merge_request: merge_request).pluck(:issue_id)
expect(issue_ids).to match_array([first_issue.id, second_issue.id])
service = described_class.new(project, user, description: "not closing any issues") service = described_class.new(project, user, description: "not closing any issues")
allow(service).to receive(:execute_hooks) allow(service).to receive(:execute_hooks)
......
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