Commit 22772871 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'note-background-job' into 'master'

Background process note logic for #3948

Quick and dirty way to get *most* of the note processing out of band and into the background. Seeing some pretty nice speed bumps. Keep in mind that doing this in process results in slower and slower responses as more notes are added and more participants exist.

```
without background processing
  Completed 200 OK in 627ms (Views: 0.5ms | ActiveRecord: 32.3ms)
  Completed 200 OK in 478ms (Views: 0.8ms | ActiveRecord: 28.3ms)
  Completed 200 OK in 1107ms (Views: 0.6ms | ActiveRecord: 36.6ms)

with background processing
  Completed 200 OK in 108ms (Views: 0.6ms | ActiveRecord: 4.7ms)
  Completed 200 OK in 78ms (Views: 0.5ms | ActiveRecord: 4.5ms)
  Completed 200 OK in 164ms (Views: 0.5ms | ActiveRecord: 8.3ms)
```

As you can see, speeds are consistent when doing the harder work out of process. I'm not sure the number of sql queries we're saving, but based on the logs alone it's a pretty good amount.

@dzaporozhets @yorickpeterse I would love some input on this.

See merge request !2631
parents e221990e f3d4f2ea
......@@ -106,7 +106,7 @@ class Projects::NotesController < Projects::ApplicationController
{ notes_left: [note], notes_right: [] }
else
{ notes_left: [], notes_right: [note] }
end
end
else
template = "projects/notes/_diff_notes_with_reply"
locals = { notes: [note] }
......
......@@ -6,27 +6,12 @@ module Notes
note.system = false
if note.save
notification_service.new_note(note)
# Skip system notes, like status changes and cross-references and awards
unless note.system || note.is_award
event_service.leave_note(note, note.author)
note.create_cross_references!
execute_hooks(note)
end
# Finish the harder work in the background
NewNoteWorker.perform_in(2.seconds, note.id, params)
end
note
end
def hook_data(note)
Gitlab::NoteDataBuilder.build(note, current_user)
end
def execute_hooks(note)
note_data = hook_data(note)
note.project.execute_hooks(note_data, :note_hooks)
note.project.execute_services(note_data, :note_hooks)
end
end
end
module Notes
class PostProcessService
attr_accessor :note
def initialize(note)
@note = note
end
def execute
# Skip system notes, like status changes and cross-references and awards
unless @note.system || @note.is_award
EventCreateService.new.leave_note(@note, @note.author)
@note.create_cross_references!
execute_note_hooks
end
end
def hook_data
Gitlab::NoteDataBuilder.build(@note, @note.author)
end
def execute_note_hooks
note_data = hook_data
@note.project.execute_hooks(note_data, :note_hooks)
@note.project.execute_services(note_data, :note_hooks)
end
end
end
class NewNoteWorker
include Sidekiq::Worker
sidekiq_options queue: :default
def perform(note_id, note_params)
note = Note.find(note_id)
NotificationService.new.new_note(note)
Notes::PostProcessService.new(note).execute
end
end
......@@ -14,9 +14,7 @@ describe Notes::CreateService, services: true do
noteable_type: 'Issue',
noteable_id: issue.id
}
expect(project).to receive(:execute_hooks)
expect(project).to receive(:execute_services)
@note = Notes::CreateService.new(project, user, opts).execute
end
......
require 'spec_helper'
describe Notes::PostProcessService, services: true do
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let(:user) { create(:user) }
describe :execute do
before do
project.team << [user, :master]
note_opts = {
note: 'Awesome comment',
noteable_type: 'Issue',
noteable_id: issue.id
}
@note = Notes::CreateService.new(project, user, note_opts).execute
end
it do
expect(project).to receive(:execute_hooks)
expect(project).to receive(:execute_services)
Notes::PostProcessService.new(@note).execute
end
end
end
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