mirror of
https://github.com/discourse/discourse.git
synced 2025-06-02 04:08:41 +08:00
PERF: fix performance of chat email notifications
When chat is enabled, there's a scheduled job that runs every 5 minutes to check whether we need to send a "chat summary" email to users with unread chat messages or mentions. On Discourse with a large number of users, the query used wasn't optimal and sometimes taking minutes. Which isn't good when the query is called every 5 minutes 😬 This PR reworks the query in `Chat::Mailer.send_unread_mentions_summary`. Instead of starting from the `users` table, it starts from the `user_chat_channel_memberships` table which is the main piece tying everything together. The new query is mostly similar to the previous one, with some bug fixes (like ensuring the user has `allow_private_messages` enabled for direct messages) and is also slightly simpler since it doesn't keep track of the `memberships_with_unread_messages` anymore. That part has been moved to the `user_notifications.chat_summary` email method. The `UserEmailExtension` has been deleted since that was using to N+1 update the `user_chat_channel_memberships.last_unread_mention_when_emailed_it`(quite a mouthful 😛) but that's now done directly in the `user_notifications.chat_summary` email method. The "plat de résistance" of that PR - the `user_notifications.chat_summary` method has been re-worked for improved performances 🚀 Instead of doing everything in one query, it does 4 tiny ones. - One to retrieve the list of unread mentions (@something) in "category" channels - One to retrieve the list of unread messages in "direct message" channels (aka. 1-1 and group discussions) - One to load all the chat messages for each "category" channels from the last unread mention - One to load all the chat messages for each "direct message" channels from the last unread message All the specs for both `Chat::Mailer` and `UserNotification.chat_summary` have been rewriten for easier comprehension and faster execution (mostly by not using chat services which makes the specs go 10x slower...) Internal ref - t/129848
This commit is contained in:
@ -21,7 +21,7 @@ module Chat
|
||||
end
|
||||
|
||||
def generate_auto_slug
|
||||
false if !self.slug.present?
|
||||
self.slug.blank?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -4,7 +4,7 @@ module Chat
|
||||
class MentionNotification < ActiveRecord::Base
|
||||
self.table_name = "chat_mention_notifications"
|
||||
|
||||
belongs_to :chat_mention
|
||||
belongs_to :chat_mention, class_name: "Chat::Mention"
|
||||
belongs_to :notification, dependent: :destroy
|
||||
end
|
||||
end
|
||||
|
@ -2,7 +2,6 @@
|
||||
<table class="chat-summary-header text-header with-dir" style="background-color:#<%= @header_bgcolor -%>;width:100%;min-width:100%;">
|
||||
<tr>
|
||||
<td align="center" style="text-align: center;padding: 20px 0; font-family:Arial,sans-serif;">
|
||||
|
||||
<a href="<%= Discourse.base_url %>" style="color:#<%= @header_color -%>;font-size:22px;text-decoration:none;">
|
||||
<%- if logo_url.blank? %>
|
||||
<%= SiteSetting.title %>
|
||||
@ -10,73 +9,68 @@
|
||||
<img src="<%= logo_url %>" height="40" style="clear:both;display:block;height:40px;margin:auto;max-width:100%;outline:0;text-decoration:none;" alt="<%= SiteSetting.title %>">
|
||||
<%- end %>
|
||||
</a>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="font-weight:bold;font-size:22px;color:#<%= @header_color -%>">
|
||||
<%= I18n.t("user_notifications.chat_summary.description", count: @messages.size) %>
|
||||
<%= I18n.t("user_notifications.chat_summary.description", count: @count) %>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<%- @grouped_messages.each do |chat_channel, messages| %>
|
||||
<%- other_messages_count = messages.size - 2 %>
|
||||
<table class="chat-summary-content" style="padding:1em;margin-top:20px;width:100%;min-width:100%;background-color:#f7f7f7;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="100%">
|
||||
<h5 style="margin:0.5em 0 0.5em 0;font-size:0.9em;">
|
||||
<%- if SiteSetting.private_email %>
|
||||
<%= I18n.t("system_messages.private_channel_title", id: chat_channel.id) %>
|
||||
<%- else %>
|
||||
<%= chat_channel.title(@user) %>
|
||||
<%- end %>
|
||||
</h5>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<%- unless SiteSetting.private_email %>
|
||||
<%- messages.take(2).each do |chat_message| %>
|
||||
<%- sender = chat_message.user %>
|
||||
<%- sender_name = @display_usernames ? sender.username : sender.name %>
|
||||
|
||||
<tr class="message-row">
|
||||
<td style="white-space:nowrap;vertical-align:top;padding:<%= rtl? ? '1em 2em 0 0' : '1em 0 0 2em' %>">
|
||||
<img src="<%= sender.small_avatar_url -%>" style="height:20px;width:20px;margin:<%= rtl? ? '0 0 5px 0' : '0 5px 0 0' %>;border-radius:50%;clear:both;display:inline-block;outline:0;text-decoration:none;vertical-align:top;" alt="<%= sender_name -%>">
|
||||
<span style="display:inline-block;color:#0a0a0a;vertical-align:top;font-weight:bold;">
|
||||
<%= sender_name -%>
|
||||
</span>
|
||||
<span style="display:inline-block;color:#0a0a0a;font-size:0.8em;">
|
||||
<%= I18n.l(@user_tz.to_local(chat_message.created_at), format: :long) -%>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width:99%;margin:0;padding:<%= rtl? ? '0 2em 0 0' : '0 0 0 2em' %>;vertical-align:top;">
|
||||
<%= email_excerpt(chat_message.cooked_for_excerpt) %>
|
||||
</td>
|
||||
</tr>
|
||||
<%- end %>
|
||||
<%- end %>
|
||||
|
||||
<tr>
|
||||
<td colspan="100%" style="padding:<%= rtl? ? '2em 2em 0 0' : '2em 0 0 2em' %>">
|
||||
<a class="more-messages-link" href="<%= messages.first.full_url %>">
|
||||
<%- if SiteSetting.private_email %>
|
||||
<%= I18n.t("user_notifications.chat_summary.view_messages", count: messages.size)%>
|
||||
<%- else %>
|
||||
<%- if other_messages_count <= 0 %>
|
||||
<%= I18n.t("user_notifications.chat_summary.view_messages", count: messages.size)%>
|
||||
<%- [@grouped_channels, @grouped_dms].each do |grouped_messages| %>
|
||||
<%- grouped_messages.each do |channel, messages| %>
|
||||
<%- other_messages_count = messages.size - 2 %>
|
||||
<table class="chat-summary-content" style="padding:1em;margin-top:20px;width:100%;min-width:100%;background-color:#f7f7f7;">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td colspan="100%">
|
||||
<h5 style="margin:0.5em 0 0.5em 0;font-size:0.9em;">
|
||||
<%- if SiteSetting.private_email %>
|
||||
<%= I18n.t("system_messages.private_channel_title", id: channel.id) %>
|
||||
<%- else %>
|
||||
<%= I18n.t("user_notifications.chat_summary.view_more", count: other_messages_count)%>
|
||||
<%= channel.title(@user) %>
|
||||
<%- end %>
|
||||
<%- end %>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</h5>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<%- unless SiteSetting.private_email %>
|
||||
<%- messages.take(2).each do |chat_message| %>
|
||||
<%- sender = chat_message.user %>
|
||||
<tr class="message-row">
|
||||
<td style="white-space:nowrap;vertical-align:top;padding:<%= rtl? ? '1em 2em 0 0' : '1em 0 0 2em' %>">
|
||||
<img src="<%= sender.small_avatar_url -%>" style="height:20px;width:20px;margin:<%= rtl? ? '0 0 5px 0' : '0 5px 0 0' %>;border-radius:50%;clear:both;display:inline-block;outline:0;text-decoration:none;vertical-align:top;" alt="<%= sender.display_name -%>">
|
||||
<span style="display:inline-block;color:#0a0a0a;vertical-align:top;font-weight:bold;">
|
||||
<%= sender.display_name -%>
|
||||
</span>
|
||||
<span style="display:inline-block;color:#0a0a0a;font-size:0.8em;">
|
||||
<%= I18n.l(@user_tz.to_local(chat_message.created_at), format: :long) -%>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="width:99%;margin:0;padding:<%= rtl? ? '0 2em 0 0' : '0 0 0 2em' %>;vertical-align:top;">
|
||||
<%= email_excerpt(chat_message.cooked_for_excerpt) %>
|
||||
</td>
|
||||
</tr>
|
||||
<%- end %>
|
||||
<%- end %>
|
||||
|
||||
<tr>
|
||||
<td colspan="100%" style="padding:<%= rtl? ? '2em 2em 0 0' : '2em 0 0 2em' %>">
|
||||
<a class="more-messages-link" href="<%= messages.first.full_url %>">
|
||||
<%- if SiteSetting.private_email || other_messages_count <= 0 %>
|
||||
<%= I18n.t("user_notifications.chat_summary.view_messages", count: messages.size) %>
|
||||
<%- else %>
|
||||
<%= I18n.t("user_notifications.chat_summary.view_more", count: other_messages_count) %>
|
||||
<%- end %>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<%- end %>
|
||||
<%- end %>
|
||||
</div>
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<%- site_link = raw(@markdown_linker.create(@site_name, '/')) %>
|
||||
<%= t('user_notifications.chat_summary.description', count: @messages.size,) %>
|
||||
<%= raw(@markdown_linker.create(t("user_notifications.chat_summary.view_messages", count: @messages.size), "/chat")) %>
|
||||
<%= t('user_notifications.chat_summary.description', count: @count,) %>
|
||||
<%= raw(@markdown_linker.create(t("user_notifications.chat_summary.view_messages", count: @count), "/chat")) %>
|
||||
<%- if @unsubscribe_link %>
|
||||
<%= raw(t :'user_notifications.chat_summary.unsubscribe',
|
||||
site_link: site_link,
|
||||
@ -11,5 +11,4 @@
|
||||
site_link: site_link,
|
||||
email_preferences_link: @markdown_linker.create(t('user_notifications.chat_summary.your_chat_settings'), @preferences_path)) %>
|
||||
<%- end %>
|
||||
|
||||
<%= raw(@markdown_linker.references) %>
|
||||
<%= raw(@markdown_linker.references) %>
|
Reference in New Issue
Block a user