DEV: Chat thread reply counter cache (#21050)

Similar to 22a55ef0ce42823b860f2d3432e4d7f14a00752f,
this commit adds a replies_count to the Chat::Thread
table, which is updated every 15 minutes via PeriodicalUpdates.
This is done so the new thread indicator for the UI can
show the count without intense serializer queries, but
in future we likely want this to update more frequently.
This commit is contained in:
Martin Brennan
2023-04-11 15:40:25 +10:00
committed by GitHub
parent 90172e5a9e
commit e34fb7e0b2
9 changed files with 157 additions and 21 deletions

View File

@ -9,6 +9,7 @@ module Jobs
# TODO: Add rebaking of old messages (baked_version <
# Chat::Message::BAKED_VERSION or baked_version IS NULL)
::Chat::Channel.ensure_consistency!
::Chat::Thread.ensure_consistency!
nil
end
end

View File

@ -165,32 +165,33 @@ end
#
# Table name: chat_channels
#
# id :bigint not null, primary key
# chatable_id :integer not null
# deleted_at :datetime
# deleted_by_id :integer
# featured_in_category_id :integer
# delete_after_seconds :integer
# chatable_type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# name :string
# description :text
# status :integer default("open"), not null
# user_count :integer default(0), not null
# last_message_sent_at :datetime not null
# auto_join_users :boolean default(FALSE), not null
# allow_channel_wide_mentions :boolean default(TRUE), not null
# user_count_stale :boolean default(FALSE), not null
# slug :string
# type :string
# threading_enabled :boolean default(FALSE), not null
# id :bigint not null, primary key
# chatable_id :integer not null
# deleted_at :datetime
# deleted_by_id :integer
# featured_in_category_id :integer
# delete_after_seconds :integer
# chatable_type :string not null
# created_at :datetime not null
# updated_at :datetime not null
# name :string
# description :text
# status :integer default("open"), not null
# user_count :integer default(0), not null
# last_message_sent_at :datetime not null
# auto_join_users :boolean default(FALSE), not null
# user_count_stale :boolean default(FALSE), not null
# slug :string
# type :string
# allow_channel_wide_mentions :boolean default(TRUE), not null
# messages_count :integer default(0), not null
# threading_enabled :boolean default(FALSE), not null
#
# Indexes
#
# index_chat_channels_on_messages_count (messages_count)
# index_chat_channels_on_chatable_id (chatable_id)
# index_chat_channels_on_chatable_id_and_chatable_type (chatable_id,chatable_type)
# index_chat_channels_on_messages_count (messages_count)
# index_chat_channels_on_slug (slug) UNIQUE
# index_chat_channels_on_status (status)
#

View File

@ -348,6 +348,7 @@ end
# Indexes
#
# idx_chat_messages_by_created_at_not_deleted (created_at) WHERE (deleted_at IS NULL)
# idx_chat_messages_by_thread_id_not_deleted (thread_id) WHERE (deleted_at IS NULL)
# index_chat_messages_on_chat_channel_id_and_created_at (chat_channel_id,created_at)
# index_chat_messages_on_chat_channel_id_and_id (chat_channel_id,id) WHERE (deleted_at IS NULL)
# index_chat_messages_on_last_editor_id (last_editor_id)

View File

@ -18,6 +18,10 @@ module Chat
enum :status, { open: 0, read_only: 1, closed: 2, archived: 3 }, scopes: false
def replies
self.chat_messages.where.not(id: self.original_message_id)
end
def url
"#{channel.url}/t/#{self.id}"
end
@ -29,6 +33,32 @@ module Chat
def excerpt
original_message.excerpt(max_length: EXCERPT_LENGTH)
end
def self.ensure_consistency!
update_counts
end
def self.update_counts
# NOTE: Chat::Thread#replies_count is not updated every time
# a message is created or deleted in a channel, the UI will lag
# behind unless it is kept in sync with MessageBus. The count
# has 1 subtracted from it to account for the original message.
#
# It is updated eventually via Jobs::Chat::PeriodicalUpdates. In
# future we may want to update this more frequently.
DB.exec <<~SQL
UPDATE chat_threads threads
SET replies_count = subquery.replies_count
FROM (
SELECT COUNT(*) - 1 AS replies_count, thread_id
FROM chat_messages
WHERE chat_messages.deleted_at IS NULL AND thread_id IS NOT NULL
GROUP BY thread_id
) subquery
WHERE threads.id = subquery.thread_id
AND subquery.replies_count != threads.replies_count
SQL
end
end
end
@ -44,6 +74,7 @@ end
# title :string
# created_at :datetime not null
# updated_at :datetime not null
# replies_count :integer default(0), not null
#
# Indexes
#
@ -51,5 +82,6 @@ end
# index_chat_threads_on_channel_id_and_status (channel_id,status)
# index_chat_threads_on_original_message_id (original_message_id)
# index_chat_threads_on_original_message_user_id (original_message_user_id)
# index_chat_threads_on_replies_count (replies_count)
# index_chat_threads_on_status (status)
#