Preload Gitaly data in ensure_merge_request_diff
Summary
Pass preload_gitaly: true in ensure_merge_request_diff so that Gitaly RPC calls (fetching commits and diffs) happen before the database transaction, reducing idle-in-transaction time during new merge request creation.
This applies the same optimization already used in ReloadDiffsService and ReloadMergeHeadDiffService to the initial diff creation path in NewMergeRequestWorker → AfterCreateService.
Details
In the production MR creation flow:
-
MergeRequests::CreateServicesetsskip_ensure_merge_request_diff = true, so theafter_createcallback onMergeRequestis skipped duringsave!. - After the transaction commits,
NewMergeRequestWorkerenqueues and callsAfterCreateService#execute. -
AfterCreateServicecallsmerge_request.ensure_merge_request_diffdirectly — outside any DB transaction. -
ensure_merge_request_diffcallscreate_merge_request_diff(preload_gitaly: true).
With the preload_gitaly flag:
- A new
MergeRequestDiffis built (not yet persisted). -
preload_gitaly_datais called, which fetches commits and diffs from Gitaly viareversed_compare_commits_preloadedandcompare_diffs_preloaded— bothstrong_memoized. This happens outside any transaction. -
save!is then called, which opens a transaction and triggers theafter_create :save_git_contentcallback. Insidesave_git_content,save_commitsandsave_diffscall the same memoized methods, so they use cached data — no Gitaly RPCs occur inside the transaction.
Without the flag (current behavior), merge_request_diffs.create! opens a transaction first, then the after_create :save_git_content callback makes Gitaly RPCs inside the transaction, causing idle-in-transaction while waiting on Gitaly.
Test
Added specs to verify ensure_merge_request_diff passes preload_gitaly: true (or false) to create_merge_request_diff depending on the feature flag state.