PERF: Async notify users after inviting group (#12697)

PERF: Async notify users after inviting group (#12697)

Inviting a group generates a notification for each member. If this happens synchronously it may take a while, leading to a poor user experience.

diff --git a/app/jobs/regular/group_pm_alert.rb b/app/jobs/regular/group_pm_alert.rb
new file mode 100644
index 0000000..a1058bb
--- /dev/null
+++ b/app/jobs/regular/group_pm_alert.rb
@@ -0,0 +1,42 @@
+# frozen_string_literal: true
+
+module Jobs
+  class GroupPmAlert < ::Jobs::Base
+    def execute(args)
+      return unless user = User.find_by(id: args[:user_id])
+      return unless group = Group.find_by(id: args[:group_id])
+      return unless post = Post.find_by(id: args[:post_id])
+      return unless topic = post.topic
+
+      group.set_message_default_notification_levels!(topic, ignore_existing: true)
+
+      alerter = PostAlerter.new
+
+      group.users.where(
+        "group_users.notification_level = :level",
+        level: NotificationLevels.all[:tracking]
+      ).find_each do |u|
+        alerter.notify_group_summary(u, post)
+      end
+
+      notification_data = {
+        notification_type: Notification.types[:invited_to_private_message],
+        topic_id: topic.id,
+        post_number: 1,
+        data: {
+          topic_title: topic.title,
+          display_username: user.username,
+          group_id: group.id
+        }.to_json
+      }
+
+      group.users.where(
+        "group_users.notification_level in (:levels) AND user_id != :id",
+        levels: [NotificationLevels.all[:watching], NotificationLevels.all[:watching_first_post]],
+        id: user.id
+      ).find_each do |u|
+        u.notifications.create!(notification_data)
+      end
+    end
+  end
+end
diff --git a/app/models/topic.rb b/app/models/topic.rb
index 341839c..a08e31a 100644
--- a/app/models/topic.rb
+++ b/app/models/topic.rb
@@ -975,37 +975,7 @@ class Topic < ActiveRecord::Base
     if last_post
       Jobs.enqueue(:post_alert, post_id: last_post.id)
       add_small_action(user, "invited_group", group.name)
-
-      group_id = group.id
-
-      group.set_message_default_notification_levels!(self, ignore_existing: true)
-
-      group.users.where(
-        "group_users.notification_level = :level",
-        level: NotificationLevels.all[:tracking],
-        id: user.id
-      ).find_each do |u|
-        PostAlerter.new.notify_group_summary(u, last_post)
-      end
-
-      group.users.where(
-        "group_users.notification_level in (:levels) AND user_id != :id",
-        levels: [NotificationLevels.all[:watching], NotificationLevels.all[:watching_first_post]],
-        id: user.id
-      ).find_each do |u|
-
-        u.notifications.create!(
-          notification_type: Notification.types[:invited_to_private_message],
-          topic_id: self.id,
-          post_number: 1,
-          data: {
-            topic_title: self.title,
-            display_username: user.username,
-            group_id: group_id
-          }.to_json
-        )
-
-      end
+      Jobs.enqueue(:group_pm_alert, user_id: user.id, group_id: group.id, post_id: last_post.id)
     end
 
     true
diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb
index e35ee4e..81e8c19 100644
--- a/spec/models/topic_spec.rb
+++ b/spec/models/topic_spec.rb
@@ -982,6 +982,7 @@ describe Topic do
             set_state!(group, user_muted, :muted)
 
             Notification.delete_all
+            Jobs.run_immediately!
             topic.invite_group(topic.user, group)
 
             expect(Notification.count).to eq(3)
diff --git a/spec/models/topic_user_spec.rb b/spec/models/topic_user_spec.rb
index d448a09..cba1710 100644
--- a/spec/models/topic_user_spec.rb
+++ b/spec/models/topic_user_spec.rb
@@ -281,6 +281,7 @@ describe TopicUser do
           another_user = Fabricate(:user)
           group.add(another_user)
 
+          Jobs.run_immediately!
           topic.invite_group(target_user, group)
 
           expect(TopicUser.get(topic, another_user).notification_level)

GitHub sha: 99dadb21

This commit appears in #12697 which was approved by ZogStriP and eviltrout. It was merged by udan11.