diff --git a/Gemfile.lock b/Gemfile.lock index 45c54bd46..fa45d1e89 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -186,7 +186,7 @@ GEM database_cleaner-core (2.0.1) datadog-ci (0.8.3) msgpack - date (3.3.4) + date (3.4.1) ddtrace (1.23.2) datadog-ci (~> 0.8.1) debase-ruby_core_source (= 3.3.1) @@ -487,7 +487,7 @@ GEM uri net-http-persistent (4.0.2) connection_pool (~> 2.2) - net-imap (0.4.17) + net-imap (0.4.19) date net-protocol net-pop (0.1.2) @@ -782,7 +782,7 @@ GEM time_diff (0.3.0) activesupport i18n - timeout (0.4.1) + timeout (0.4.3) trailblazer-option (0.1.2) twilio-ruby (5.77.0) faraday (>= 0.9, < 3.0) diff --git a/app/jobs/action_cable_broadcast_job.rb b/app/jobs/action_cable_broadcast_job.rb index b1208a97c..ce1230029 100644 --- a/app/jobs/action_cable_broadcast_job.rb +++ b/app/jobs/action_cable_broadcast_job.rb @@ -2,8 +2,34 @@ class ActionCableBroadcastJob < ApplicationJob queue_as :critical def perform(members, event_name, data) + return if members.blank? + + broadcast_data = prepare_broadcast_data(event_name, data) + broadcast_to_members(members, event_name, broadcast_data) + end + + private + + # Ensures that only the latest available data is sent to prevent UI issues + # caused by out-of-order events during high-traffic periods. This prevents + # the conversation job from processing outdated data. + def prepare_broadcast_data(event_name, data) + return data unless event_name == 'conversation.updated' + + account = Account.find(data[:account_id]) + conversation = account.conversations.find_by!(display_id: data[:id]) + conversation.push_event_data.merge(account_id: data[:account_id]) + end + + def broadcast_to_members(members, event_name, broadcast_data) members.each do |member| - ActionCable.server.broadcast(member, { event: event_name, data: data }) + ActionCable.server.broadcast( + member, + { + event: event_name, + data: broadcast_data + } + ) end end end diff --git a/app/presenters/conversations/event_data_presenter.rb b/app/presenters/conversations/event_data_presenter.rb index 2617721ec..2ef69080d 100644 --- a/app/presenters/conversations/event_data_presenter.rb +++ b/app/presenters/conversations/event_data_presenter.rb @@ -42,7 +42,8 @@ class Conversations::EventDataPresenter < SimpleDelegator contact_last_seen_at: contact_last_seen_at.to_i, last_activity_at: last_activity_at.to_i, timestamp: last_activity_at.to_i, - created_at: created_at.to_i + created_at: created_at.to_i, + updated_at: updated_at.to_f } end end diff --git a/app/views/api/v1/conversations/partials/_conversation.json.jbuilder b/app/views/api/v1/conversations/partials/_conversation.json.jbuilder index a9a580e26..8867ba695 100644 --- a/app/views/api/v1/conversations/partials/_conversation.json.jbuilder +++ b/app/views/api/v1/conversations/partials/_conversation.json.jbuilder @@ -44,6 +44,7 @@ json.muted conversation.muted? json.snoozed_until conversation.snoozed_until json.status conversation.status json.created_at conversation.created_at.to_i +json.updated_at conversation.updated_at.to_f json.timestamp conversation.last_activity_at.to_i json.first_reply_created_at conversation.first_reply_created_at.to_i json.unread_count conversation.unread_incoming_messages.count diff --git a/spec/models/conversation_spec.rb b/spec/models/conversation_spec.rb index 5813d8c3c..1938fb204 100644 --- a/spec/models/conversation_spec.rb +++ b/spec/models/conversation_spec.rb @@ -538,6 +538,7 @@ RSpec.describe Conversation do contact_last_seen_at: conversation.contact_last_seen_at.to_i, agent_last_seen_at: conversation.agent_last_seen_at.to_i, created_at: conversation.created_at.to_i, + updated_at: conversation.updated_at.to_f, waiting_since: conversation.waiting_since.to_i, priority: nil, unread_count: 0 diff --git a/spec/presenters/conversations/event_data_presenter_spec.rb b/spec/presenters/conversations/event_data_presenter_spec.rb index f6a400b96..a645caf1d 100644 --- a/spec/presenters/conversations/event_data_presenter_spec.rb +++ b/spec/presenters/conversations/event_data_presenter_spec.rb @@ -31,6 +31,7 @@ RSpec.describe Conversations::EventDataPresenter do contact_last_seen_at: conversation.contact_last_seen_at.to_i, agent_last_seen_at: conversation.agent_last_seen_at.to_i, created_at: conversation.created_at.to_i, + updated_at: conversation.updated_at.to_f, waiting_since: conversation.waiting_since.to_i, priority: nil, unread_count: 0