Fixes #3299 - Having more active Agents using the Chat decreases performance linearly.
This commit is contained in:
parent
aaa30b2b90
commit
dccd4aa012
5 changed files with 166 additions and 8 deletions
|
@ -20,10 +20,16 @@ class Chat::Agent < ApplicationModel
|
||||||
|
|
||||||
return chat_agent.active
|
return chat_agent.active
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# ATTENTION: setter return value indicates whether `active` state has changed
|
||||||
if chat_agent
|
if chat_agent
|
||||||
chat_agent.active = state
|
chat_agent.active = state
|
||||||
|
# always update `updated_at` to inform other Agent sessions
|
||||||
|
# that this Agent session is still active
|
||||||
chat_agent.updated_at = Time.zone.now
|
chat_agent.updated_at = Time.zone.now
|
||||||
chat_agent.save
|
chat_agent.save
|
||||||
|
|
||||||
|
chat_agent.active_previously_changed?
|
||||||
else
|
else
|
||||||
Chat::Agent.create(
|
Chat::Agent.create(
|
||||||
active: state,
|
active: state,
|
||||||
|
|
|
@ -23,14 +23,7 @@ return is sent as message back to peer
|
||||||
# check if user has permissions
|
# check if user has permissions
|
||||||
return if !permission_check('chat.agent', 'chat')
|
return if !permission_check('chat.agent', 'chat')
|
||||||
|
|
||||||
chat_user = User.lookup(id: @session['id'])
|
update_state
|
||||||
|
|
||||||
Chat::Agent.state(@session['id'], @payload['data']['active'])
|
|
||||||
|
|
||||||
chat_ids = Chat.agent_active_chat_ids(chat_user)
|
|
||||||
|
|
||||||
# broadcast new state to agents
|
|
||||||
Chat.broadcast_agent_state_update(chat_ids, @session['id'])
|
|
||||||
|
|
||||||
{
|
{
|
||||||
event: 'chat_agent_state',
|
event: 'chat_agent_state',
|
||||||
|
@ -41,4 +34,17 @@ return is sent as message back to peer
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def update_state
|
||||||
|
chat_user = User.lookup(id: @session['id'])
|
||||||
|
|
||||||
|
return if !Chat::Agent.state(@session['id'], @payload['data']['active'])
|
||||||
|
|
||||||
|
chat_ids = Chat.agent_active_chat_ids(chat_user)
|
||||||
|
|
||||||
|
# broadcast new state to agents
|
||||||
|
Chat.broadcast_agent_state_update(chat_ids, @session['id'])
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
factory :'chat/agent' do
|
factory :'chat/agent' do
|
||||||
|
active { true }
|
||||||
created_by_id { 1 }
|
created_by_id { 1 }
|
||||||
updated_by_id { 1 }
|
updated_by_id { 1 }
|
||||||
end
|
end
|
||||||
|
|
63
spec/lib/sessions/event/chat_agent_state_spec.rb
Normal file
63
spec/lib/sessions/event/chat_agent_state_spec.rb
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe Sessions::Event::ChatAgentState do
|
||||||
|
|
||||||
|
let(:client_id) { rand(123_456_789) }
|
||||||
|
let(:chat) { Chat.first }
|
||||||
|
|
||||||
|
let(:user) do
|
||||||
|
create(:agent, preferences: {
|
||||||
|
chat: {
|
||||||
|
active: {
|
||||||
|
chat.id.to_s => 'on'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:instance) do
|
||||||
|
Sessions.create(client_id, { 'id' => user.id }, {})
|
||||||
|
Sessions.queue(client_id)
|
||||||
|
described_class.new(
|
||||||
|
payload: {
|
||||||
|
'data' => {
|
||||||
|
'active' => active
|
||||||
|
},
|
||||||
|
},
|
||||||
|
user_id: user.id,
|
||||||
|
client_id: client_id,
|
||||||
|
clients: {},
|
||||||
|
session: {
|
||||||
|
'id' => user.id
|
||||||
|
},
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:record) { create(:'chat/agent', updated_by: user) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
Setting.set('chat', true)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when state changes' do
|
||||||
|
|
||||||
|
let(:active) { !record.active }
|
||||||
|
|
||||||
|
it 'broadcasts agent state update' do
|
||||||
|
allow(Chat).to receive(:broadcast_agent_state_update)
|
||||||
|
instance.run
|
||||||
|
expect(Chat).to have_received(:broadcast_agent_state_update)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when state doesn't change" do
|
||||||
|
|
||||||
|
let(:active) { record.active }
|
||||||
|
|
||||||
|
it "doesn't broadcasts agent state update" do
|
||||||
|
allow(Chat).to receive(:broadcast_agent_state_update)
|
||||||
|
instance.run
|
||||||
|
expect(Chat).not_to have_received(:broadcast_agent_state_update)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
82
spec/models/chat/agent_spec.rb
Normal file
82
spec/models/chat/agent_spec.rb
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe Chat::Agent, type: :model do
|
||||||
|
|
||||||
|
describe '.state' do
|
||||||
|
|
||||||
|
let(:user) { create(:agent) }
|
||||||
|
|
||||||
|
context 'when no record exists for User' do
|
||||||
|
|
||||||
|
it 'returns false' do
|
||||||
|
expect(described_class.state(1337)).to be(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when active flag is set to true' do
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:'chat/agent', active: true, updated_by: user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns true' do
|
||||||
|
expect(described_class.state(user.id)).to be(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when active flag is set to false' do
|
||||||
|
|
||||||
|
before do
|
||||||
|
create(:'chat/agent', active: false, updated_by: user)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns false' do
|
||||||
|
expect(described_class.state(user.id)).to be(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when setting state for not existing record' do
|
||||||
|
it 'creates a record' do
|
||||||
|
expect { described_class.state(user.id, true) }.to change { described_class.exists?(updated_by: user) }.from(false).to(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when setting same state for record' do
|
||||||
|
|
||||||
|
let(:record) { create(:'chat/agent', active: true, updated_by: user) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
# avoid race condition with same updated_at time
|
||||||
|
record
|
||||||
|
travel_to 5.minutes.from_now
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates updated_at timestamp' do
|
||||||
|
expect { described_class.state(record.updated_by_id, record.active) }.to change { record.reload.updated_at }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns false' do
|
||||||
|
expect(described_class.state(record.updated_by_id, record.active)).to eq(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when setting different state for record' do
|
||||||
|
|
||||||
|
let(:record) { create(:'chat/agent', active: true, updated_by: user) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
# avoid race condition with same updated_at time
|
||||||
|
record
|
||||||
|
travel_to 5.minutes.from_now
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates updated_at timestamp' do
|
||||||
|
expect { described_class.state(record.updated_by_id, !record.active) }.to change { record.reload.updated_at }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns true' do
|
||||||
|
expect(described_class.state(record.updated_by_id, !record.active)).to eq(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue