Fix timeout in approval checks by querying committer emails via SQL
Summary
- The approval mergeability check (
committers_to_filter_from_approvers,committer_ids_to_filter_from_approvers) was callingcommitters()which instantiates allMergeRequestDiffCommitRuby objects, preloads associations, and converts each to aCommit— just to extract committer emails. For MRs with thousands of commits, this caused 60s+ CPU timeouts. - Introduces
committer_emails_from_diffwhich queries committer emails directly via an Arel-built UNION query (merge_request_diff_commits→merge_request_commits_metadata→merge_request_diff_commit_users), bypassing all Ruby object instantiation. - Only the approval-specific methods use the new query path. The general
committers()method is left unchanged for other callers. - Gated behind the
approval_committer_emails_from_difffeature flag (gitlab_com_derisk, default disabled).
Why the SQL-only approach is safe
The approval callers invoke committers(with_merge_commits: true, include_author_when_signed: true). These parameters have the following effects:
-
with_merge_commits: true— This skips thewithout_merge_commitsfilter entirely (CommitCollection#committers_emailsline 172 returns early), so all commits are included. Our SQL query also includes all commits — equivalent behavior. -
include_author_when_signed: true— This causescommitter_emails_forto checkcommit.signature&.verified_system?and returnauthor_emailinstead ofcommitter_emailwhen true. However,Commit.from_hashcreates commits without Gitaly backing, soraw_signature_typereturns nil →signaturereturns nil →verified_system?is never reached. The code always falls through tocommitter_email. Our SQL query extracts the same committer emails directly. -
Maps committer emails to
Userrecords — this is the only meaningful work. The new query extracts the same emails directly from the database and passes them toUser.by_any_email, producing identical results without instantiating thousands of intermediate Ruby objects.
SQL Queries
Edited by Marc Shaw