From e56132c50692771b3d315d944e3a279852a4251e Mon Sep 17 00:00:00 2001 From: Subin T P Date: Sun, 29 Mar 2020 19:18:30 +0530 Subject: [PATCH] Non blocking event dispatch (#652) - Performance improvements for event dispatch --- app/dispatchers/async_dispatcher.rb | 5 ++++- app/jobs/event_dispatcher_job.rb | 7 +++++++ config/sidekiq.yml | 3 ++- spec/builders/v2/report_builder_spec.rb | 10 ++++++++++ spec/dispatchers/async_dispatcher_spec.rb | 16 ++++++++++++++++ spec/jobs/event_dispatcher_job_spec.rb | 22 ++++++++++++++++++++++ 6 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 app/jobs/event_dispatcher_job.rb create mode 100644 spec/dispatchers/async_dispatcher_spec.rb create mode 100644 spec/jobs/event_dispatcher_job_spec.rb diff --git a/app/dispatchers/async_dispatcher.rb b/app/dispatchers/async_dispatcher.rb index cce44c97a..65569c1b0 100644 --- a/app/dispatchers/async_dispatcher.rb +++ b/app/dispatchers/async_dispatcher.rb @@ -1,7 +1,10 @@ class AsyncDispatcher < BaseDispatcher def dispatch(event_name, timestamp, data) + EventDispatcherJob.perform_later(event_name, timestamp, data) + end + + def publish_event(event_name, timestamp, data) event_object = Events::Base.new(event_name, timestamp, data) - # TODO: Move this to worker publish(event_object.method_name, event_object) end diff --git a/app/jobs/event_dispatcher_job.rb b/app/jobs/event_dispatcher_job.rb new file mode 100644 index 000000000..c08d52d74 --- /dev/null +++ b/app/jobs/event_dispatcher_job.rb @@ -0,0 +1,7 @@ +class EventDispatcherJob < ApplicationJob + queue_as :events + + def perform(event_name, timestamp, data) + Rails.configuration.dispatcher.async_dispatcher.publish_event(event_name, timestamp, data) + end +end diff --git a/config/sidekiq.yml b/config/sidekiq.yml index 8dc7f5ede..b876886ee 100644 --- a/config/sidekiq.yml +++ b/config/sidekiq.yml @@ -17,7 +17,8 @@ - [mailers, 2] - [webhooks, 1] - [bots, 1] - + - [events, 3] + # you can override concurrency based on environment production: :concurrency: 10 diff --git a/spec/builders/v2/report_builder_spec.rb b/spec/builders/v2/report_builder_spec.rb index 02a2fc4ab..4aef6c425 100644 --- a/spec/builders/v2/report_builder_spec.rb +++ b/spec/builders/v2/report_builder_spec.rb @@ -6,6 +6,16 @@ describe ::V2::ReportBuilder do let!(:inbox) { create(:inbox, account: account) } let(:inbox_member) { create(:inbox_member, user: user, inbox: inbox) } + # Running jobs inline to calculate the exact metrics + around do |test| + current_adapter = ActiveJob::Base.queue_adapter + ActiveJob::Base.queue_adapter = :inline + + test.run + ensure + ActiveJob::Base.queue_adapter = current_adapter + end + describe '#timeseries' do context 'when report type is account' do before do diff --git a/spec/dispatchers/async_dispatcher_spec.rb b/spec/dispatchers/async_dispatcher_spec.rb new file mode 100644 index 000000000..b108fd962 --- /dev/null +++ b/spec/dispatchers/async_dispatcher_spec.rb @@ -0,0 +1,16 @@ +require 'rails_helper' +describe AsyncDispatcher do + subject(:dispatcher) { described_class.new } + + let!(:conversation) { create(:conversation) } + let(:event_name) { 'conversation.created' } + let(:timestamp) { Time.zone.now } + let(:event_data) { { conversation: conversation } } + + describe '#dispatch' do + it 'enqueue job to dispatch event' do + expect(EventDispatcherJob).to receive(:perform_later).with(event_name, timestamp, event_data).once + dispatcher.dispatch(event_name, timestamp, event_data) + end + end +end diff --git a/spec/jobs/event_dispatcher_job_spec.rb b/spec/jobs/event_dispatcher_job_spec.rb new file mode 100644 index 000000000..14da570b2 --- /dev/null +++ b/spec/jobs/event_dispatcher_job_spec.rb @@ -0,0 +1,22 @@ +require 'rails_helper' + +RSpec.describe EventDispatcherJob, type: :job do + subject(:job) { described_class.perform_later(event_name, timestamp, event_data) } + + let!(:conversation) { create(:conversation) } + let(:event_name) { 'conversation.created' } + let(:timestamp) { Time.zone.now } + let(:event_data) { { conversation: conversation } } + + it 'queues the job' do + expect { job }.to have_enqueued_job(described_class) + .with(event_name, timestamp, event_data) + .on_queue('events') + end + + it 'publishes event' do + expect(Rails.configuration.dispatcher.async_dispatcher).to receive(:publish_event).with(event_name, timestamp, event_data).once + event_dispatcher = described_class.new + event_dispatcher.perform(event_name, timestamp, event_data) + end +end