feat(perf): Cache labels on the conversation model (#8527)
This commit is contained in:
@@ -14,7 +14,8 @@ class Api::V1::Accounts::Conversations::AssignmentsController < Api::V1::Account
|
||||
|
||||
def set_agent
|
||||
@agent = Current.account.users.find_by(id: params[:assignee_id])
|
||||
@conversation.update_assignee(@agent)
|
||||
@conversation.assignee = @agent
|
||||
@conversation.save!
|
||||
render_agent
|
||||
end
|
||||
|
||||
|
||||
@@ -110,8 +110,8 @@ class Api::V1::Accounts::ConversationsController < Api::V1::Accounts::BaseContro
|
||||
end
|
||||
|
||||
def assign_conversation
|
||||
@agent = Current.account.users.find(current_user.id)
|
||||
@conversation.update_assignee(@agent)
|
||||
@conversation.assignee = current_user
|
||||
@conversation.save!
|
||||
end
|
||||
|
||||
def conversation
|
||||
|
||||
16
app/jobs/migration/conversation_cache_label_job.rb
Normal file
16
app/jobs/migration/conversation_cache_label_job.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
class Migration::ConversationCacheLabelJob < ApplicationJob
|
||||
queue_as :async_database_migration
|
||||
|
||||
# To cache the label, we simply access it from the object and save it. Anytime the object is
|
||||
# saved in the future, ActsAsTaggable will automatically recompute it. This process is done
|
||||
# initially when the user has not performed any action.
|
||||
# Reference: https://github.com/mbleigh/acts-as-taggable-on/wiki/Caching
|
||||
def perform(account)
|
||||
account.conversations.find_in_batches do |conversation_batch|
|
||||
conversation_batch.each do |conversation|
|
||||
conversation.label_list
|
||||
conversation.save!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -6,6 +6,7 @@
|
||||
# additional_attributes :jsonb
|
||||
# agent_last_seen_at :datetime
|
||||
# assignee_last_seen_at :datetime
|
||||
# cached_label_list :string
|
||||
# contact_last_seen_at :datetime
|
||||
# custom_attributes :jsonb
|
||||
# first_reply_created_at :datetime
|
||||
@@ -144,10 +145,6 @@ class Conversation < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def update_assignee(agent = nil)
|
||||
update!(assignee: agent)
|
||||
end
|
||||
|
||||
def toggle_status
|
||||
# FIXME: implement state machine with aasm
|
||||
self.status = open? ? :resolved : :open
|
||||
@@ -185,6 +182,10 @@ class Conversation < ApplicationRecord
|
||||
Conversations::EventDataPresenter.new(self).push_data
|
||||
end
|
||||
|
||||
def cached_label_list_array
|
||||
(cached_label_list || '').split(',')
|
||||
end
|
||||
|
||||
def notifiable_assignee_change?
|
||||
return false unless saved_change_to_assignee_id?
|
||||
return false if assignee_id.blank?
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
json.meta do
|
||||
json.labels @conversation.label_list
|
||||
json.labels @conversation.cached_label_list_array
|
||||
json.additional_attributes @conversation.additional_attributes
|
||||
json.contact @conversation.contact.push_event_data
|
||||
json.assignee @conversation.assignee.push_event_data if @conversation.assignee.present?
|
||||
|
||||
@@ -35,7 +35,7 @@ json.can_reply conversation.can_reply?
|
||||
json.contact_last_seen_at conversation.contact_last_seen_at.to_i
|
||||
json.custom_attributes conversation.custom_attributes
|
||||
json.inbox_id conversation.inbox_id
|
||||
json.labels conversation.label_list
|
||||
json.labels conversation.cached_label_list_array
|
||||
json.muted conversation.muted?
|
||||
json.snoozed_until conversation.snoozed_until
|
||||
json.status conversation.status
|
||||
|
||||
19
db/migrate/20231211010807_add_cached_labels_list.rb
Normal file
19
db/migrate/20231211010807_add_cached_labels_list.rb
Normal file
@@ -0,0 +1,19 @@
|
||||
class AddCachedLabelsList < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
add_column :conversations, :cached_label_list, :string
|
||||
Conversation.reset_column_information
|
||||
ActsAsTaggableOn::Taggable::Cache.included(Conversation)
|
||||
|
||||
update_exisiting_conversations
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_exisiting_conversations
|
||||
::Account.find_in_batches do |account_batch|
|
||||
account_batch.each do |account|
|
||||
Migration::ConversationCacheLabelJob.perform_later(account)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[7.0].define(version: 2023_12_01_014644) do
|
||||
ActiveRecord::Schema[7.0].define(version: 2023_12_11_010807) do
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "pg_stat_statements"
|
||||
enable_extension "pg_trgm"
|
||||
@@ -453,6 +453,7 @@ ActiveRecord::Schema[7.0].define(version: 2023_12_01_014644) do
|
||||
t.integer "priority"
|
||||
t.bigint "sla_policy_id"
|
||||
t.datetime "waiting_since"
|
||||
t.string "cached_label_list"
|
||||
t.index ["account_id", "display_id"], name: "index_conversations_on_account_id_and_display_id", unique: true
|
||||
t.index ["account_id", "id"], name: "index_conversations_on_id_and_account_id"
|
||||
t.index ["account_id", "inbox_id", "status", "assignee_id"], name: "conv_acid_inbid_stat_asgnid_idx"
|
||||
|
||||
@@ -63,47 +63,4 @@ shared_examples_for 'assignment_handler' do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#update_assignee' do
|
||||
subject(:update_assignee) { conversation.update_assignee(agent) }
|
||||
|
||||
let(:conversation) { create(:conversation, assignee: nil) }
|
||||
let(:agent) do
|
||||
create(:user, email: 'agent@example.com', account: conversation.account, role: :agent)
|
||||
end
|
||||
let(:assignment_mailer) { instance_double(AgentNotifications::ConversationNotificationsMailer, deliver: true) }
|
||||
|
||||
before do
|
||||
create(:inbox_member, user: agent, inbox: conversation.inbox)
|
||||
end
|
||||
|
||||
it 'assigns the agent to conversation' do
|
||||
expect(update_assignee).to be(true)
|
||||
expect(conversation.reload.assignee).to eq(agent)
|
||||
end
|
||||
|
||||
it 'dispaches assignee changed event' do
|
||||
# TODO: FIX me
|
||||
# expect(EventDispatcherJob).to(have_been_enqueued.at_least(:once).with('assignee.changed', anything, anything, anything, anything))
|
||||
expect(EventDispatcherJob).to(have_been_enqueued.at_least(:once))
|
||||
expect(update_assignee).to be(true)
|
||||
end
|
||||
|
||||
it 'adds assignee to conversation participants' do
|
||||
expect { update_assignee }.to change { conversation.conversation_participants.count }.by(1)
|
||||
end
|
||||
|
||||
context 'when agent is current user' do
|
||||
before do
|
||||
Current.user = agent
|
||||
end
|
||||
|
||||
it 'creates self-assigned message activity' do
|
||||
expect(update_assignee).to be(true)
|
||||
expect(Conversations::ActivityMessageJob).to(have_been_enqueued.at_least(:once)
|
||||
.with(conversation, { account_id: conversation.account_id, inbox_id: conversation.inbox_id,
|
||||
message_type: :activity, content: "#{agent.name} self-assigned this conversation" }))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user