diff options
author | Sean McGivern <sean@gitlab.com> | 2018-04-20 19:37:38 +0200 |
---|---|---|
committer | Sean McGivern <sean@gitlab.com> | 2018-04-25 12:48:14 +0100 |
commit | b5042e5301e86ec7822221ee29679b0fbf5c71ca (patch) | |
tree | 48d02d3b6b52c94015d5bb6509db3807056e3dff /app/services/notification_service.rb | |
parent | fd532302ecb04159ce1299f1b312fe622147849c (diff) | |
download | gitlab-ce-b5042e5301e86ec7822221ee29679b0fbf5c71ca.tar.gz |
Move NotificationService calls to Sidekiq
The NotificationService has to do quite a lot of work to calculate the
recipients for an email. Where possible, we should try to avoid doing this in an
HTTP request, because the mail are sent by Sidekiq anyway, so there's no need to
schedule those emails immediately.
This commit creates a generic Sidekiq worker that uses Global ID to serialise
and deserialise its arguments, then forwards them to the NotificationService.
The NotificationService gains an `#async` method, so you can replace:
notification_service.new_issue(issue, current_user)
With:
notification_service.async.new_issue(issue, current_user)
And have everything else work as normal, except that calculating the recipients
will be done by Sidekiq, which will then schedule further Sidekiq jobs to send
each email.
Diffstat (limited to 'app/services/notification_service.rb')
-rw-r--r-- | app/services/notification_service.rb | 75 |
1 files changed, 42 insertions, 33 deletions
diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 274161df946..55a1735e54b 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -7,7 +7,32 @@ # Ex. # NotificationService.new.new_issue(issue, current_user) # +# When calculating the recipients of a notification is expensive (for instance, +# in the new issue case), `#async` will make that calculation happen in Sidekiq +# instead: +# +# NotificationService.new.async.new_issue(issue, current_user) +# class NotificationService + class Async + attr_reader :parent + delegate :respond_to_missing, to: :parent + + def initialize(parent) + @parent = parent + end + + def method_missing(meth, *args) + return super unless parent.respond_to?(meth) + + MailScheduler::NotificationServiceWorker.perform_async(meth.to_s, *args) + end + end + + def async + @async ||= Async.new(self) + end + # Always notify user about ssh key added # only if ssh key is not deploy key # @@ -142,8 +167,23 @@ class NotificationService # * merge_request assignee if their notification level is not Disabled # * users with custom level checked with "reassign merge request" # - def reassigned_merge_request(merge_request, current_user) - reassign_resource_email(merge_request, current_user, :reassigned_merge_request_email) + def reassigned_merge_request(merge_request, current_user, previous_assignee) + recipients = NotificationRecipientService.build_recipients( + merge_request, + current_user, + action: "reassign", + previous_assignee: previous_assignee + ) + + recipients.each do |recipient| + mailer.reassigned_merge_request_email( + recipient.user.id, + merge_request.id, + previous_assignee&.id, + current_user.id, + recipient.reason + ).deliver_later + end end # When we add labels to a merge request we should send an email to: @@ -421,29 +461,6 @@ class NotificationService end end - def reassign_resource_email(target, current_user, method) - previous_assignee_id = previous_record(target, 'assignee_id') - previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id - - recipients = NotificationRecipientService.build_recipients( - target, - current_user, - action: "reassign", - previous_assignee: previous_assignee - ) - - recipients.each do |recipient| - mailer.send( - method, - recipient.user.id, - target.id, - previous_assignee_id, - current_user.id, - recipient.reason - ).deliver_later - end - end - def relabeled_resource_email(target, labels, current_user, method) recipients = labels.flat_map { |l| l.subscribers(target.project) }.uniq recipients = notifiable_users( @@ -471,14 +488,6 @@ class NotificationService Notify end - def previous_record(object, attribute) - return unless object && attribute - - if object.previous_changes.include?(attribute) - object.previous_changes[attribute].first - end - end - private def recipients_for_pages_domain(domain) |