Use lazy evaluation when building data for Project hooks
Summary
We have many places in our codebase where we call hooks/services, and build the data payload beforehand. This can be expensive if we need to fetch associations, and redundant if we don't actually have any hooks/services to call.
Improvements
A WIP merge request can be used as the basis for this feature: #326528 (comment 1332225711).
Expand to see the original proposal from `@toupeira` using `Lazy`
Here's an example I experimented with in !58114 (merged) (removed again in the meantime), which saved around a dozen queries in one test case:
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index 25f319da03b..fa8b847b16a 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -52,8 +52,9 @@ def create_assignee_note(issue, old_assignees)
end
def execute_hooks(issue, action = 'open', old_associations: {})
- issue_data = hook_data(issue, action, old_associations: old_associations)
+ issue_data = Gitlab::Lazy.new { hook_data(issue, action, old_associations: old_associations) }
hooks_scope = issue.confidential? ? :confidential_issue_hooks : :issue_hooks
issue.project.execute_hooks(issue_data, hooks_scope)
issue.project.execute_services(issue_data, hooks_scope)
Risks
This could introduce subtle bugs because the actual queries might run later than previously (e.g. after a DB update rather than before).
Involved components
Possibly anywhere we call execute_hooks / execute_services.
Availability & Testing
Please run package-and-qa and reach out to @sgregory2 to run e2e webhook specs.
Edited by 🤖 GitLab Bot 🤖