summaryrefslogtreecommitdiff
path: root/app/workers
diff options
context:
space:
mode:
authorRobert Speicher <robert@gitlab.com>2016-11-07 15:50:07 +0000
committerRobert Speicher <robert@gitlab.com>2016-11-07 15:50:07 +0000
commit6f307295ac792941f203381de377de7fb1c6b38a (patch)
tree57ccdcfabb0bd78d01f0ee660ec6133bf351b75f /app/workers
parent7ce03197d33e1194bed49fbd9ac7778f72d6fada (diff)
parent509910b89f636f95d2d5a9cd3f38ce8f7f4f47a6 (diff)
downloadgitlab-ce-6f307295ac792941f203381de377de7fb1c6b38a.tar.gz
Merge branch 'process-commits-using-sidekiq' into 'master'
Processing Commits Using Sidekiq This moves the code of `GitPushService#process_commit_messages` into a separate Sidekiq worker. This allows processing of commits to happen in parallel, speeding up the process. See the individual commit (messages) for more information. Part of https://gitlab.com/gitlab-org/gitlab-ce/issues/15463 See merge request !6802
Diffstat (limited to 'app/workers')
-rw-r--r--app/workers/process_commit_worker.rb67
1 files changed, 67 insertions, 0 deletions
diff --git a/app/workers/process_commit_worker.rb b/app/workers/process_commit_worker.rb
new file mode 100644
index 00000000000..071741fbacd
--- /dev/null
+++ b/app/workers/process_commit_worker.rb
@@ -0,0 +1,67 @@
+# Worker for processing individiual commit messages pushed to a repository.
+#
+# Jobs for this worker are scheduled for every commit that is being pushed. As a
+# result of this the workload of this worker should be kept to a bare minimum.
+# Consider using an extra worker if you need to add any extra (and potentially
+# slow) processing of commits.
+class ProcessCommitWorker
+ include Sidekiq::Worker
+ include DedicatedSidekiqQueue
+
+ # project_id - The ID of the project this commit belongs to.
+ # user_id - The ID of the user that pushed the commit.
+ # commit_sha - The SHA1 of the commit to process.
+ # default - The data was pushed to the default branch.
+ def perform(project_id, user_id, commit_sha, default = false)
+ project = Project.find_by(id: project_id)
+
+ return unless project
+
+ user = User.find_by(id: user_id)
+
+ return unless user
+
+ commit = find_commit(project, commit_sha)
+
+ return unless commit
+
+ author = commit.author || user
+
+ process_commit_message(project, commit, user, author, default)
+
+ update_issue_metrics(commit, author)
+ end
+
+ def process_commit_message(project, commit, user, author, default = false)
+ closed_issues = default ? commit.closes_issues(user) : []
+
+ unless closed_issues.empty?
+ close_issues(project, user, author, commit, closed_issues)
+ end
+
+ commit.create_cross_references!(author, closed_issues)
+ end
+
+ def close_issues(project, user, author, commit, issues)
+ # We don't want to run permission related queries for every single issue,
+ # therefor we use IssueCollection here and skip the authorization check in
+ # Issues::CloseService#execute.
+ IssueCollection.new(issues).updatable_by_user(user).each do |issue|
+ Issues::CloseService.new(project, author).
+ close_issue(issue, commit: commit)
+ end
+ end
+
+ def update_issue_metrics(commit, author)
+ mentioned_issues = commit.all_references(author).issues
+
+ Issue::Metrics.where(issue_id: mentioned_issues.map(&:id), first_mentioned_in_commit_at: nil).
+ update_all(first_mentioned_in_commit_at: commit.committed_date)
+ end
+
+ private
+
+ def find_commit(project, sha)
+ project.commit(sha)
+ end
+end