From 586dc800bb0d6772a9668eb5b4fe7c59df6fe82f Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Sat, 15 Mar 2025 13:51:08 -0700 Subject: [PATCH] chore: Move Twilio event processing to background job (#11094) - Twilio events were being processed synchronously, leading to slow API responses. - This change moves Twilio event processing to a background job to improve performance and align with how other events (e.g., WhatsApp) are handled. --------- Co-authored-by: Pranav --- app/controllers/twilio/callback_controller.rb | 2 +- .../twilio/delivery_status_controller.rb | 2 +- .../webhooks/twilio_delivery_status_job.rb | 8 ++++++ app/jobs/webhooks/twilio_events_job.rb | 8 ++++++ .../twilio/callbacks_controller_spec.rb | 28 +++++++++++++------ .../twilio/delivery_status_controller_spec.rb | 26 +++++++++++------ .../twilio_delivery_status_job_spec.rb | 26 +++++++++++++++++ spec/jobs/webhooks/twilio_events_job_spec.rb | 28 +++++++++++++++++++ 8 files changed, 108 insertions(+), 20 deletions(-) create mode 100644 app/jobs/webhooks/twilio_delivery_status_job.rb create mode 100644 app/jobs/webhooks/twilio_events_job.rb create mode 100644 spec/jobs/webhooks/twilio_delivery_status_job_spec.rb create mode 100644 spec/jobs/webhooks/twilio_events_job_spec.rb diff --git a/app/controllers/twilio/callback_controller.rb b/app/controllers/twilio/callback_controller.rb index 7723e5dd2..ff5db952d 100644 --- a/app/controllers/twilio/callback_controller.rb +++ b/app/controllers/twilio/callback_controller.rb @@ -1,6 +1,6 @@ class Twilio::CallbackController < ApplicationController def create - ::Twilio::IncomingMessageService.new(params: permitted_params).perform + Webhooks::TwilioEventsJob.perform_later(permitted_params.to_unsafe_hash) head :no_content end diff --git a/app/controllers/twilio/delivery_status_controller.rb b/app/controllers/twilio/delivery_status_controller.rb index cc7afb0fc..1c756a1c2 100644 --- a/app/controllers/twilio/delivery_status_controller.rb +++ b/app/controllers/twilio/delivery_status_controller.rb @@ -1,6 +1,6 @@ class Twilio::DeliveryStatusController < ApplicationController def create - ::Twilio::DeliveryStatusService.new(params: permitted_params).perform + Webhooks::TwilioDeliveryStatusJob.perform_later(permitted_params.to_unsafe_hash) head :no_content end diff --git a/app/jobs/webhooks/twilio_delivery_status_job.rb b/app/jobs/webhooks/twilio_delivery_status_job.rb new file mode 100644 index 000000000..324a17e94 --- /dev/null +++ b/app/jobs/webhooks/twilio_delivery_status_job.rb @@ -0,0 +1,8 @@ +class Webhooks::TwilioDeliveryStatusJob < ApplicationJob + queue_as :low + + def perform(params = {}) + # Process the Twilio delivery status webhook event in the background + ::Twilio::DeliveryStatusService.new(params: params).perform + end +end diff --git a/app/jobs/webhooks/twilio_events_job.rb b/app/jobs/webhooks/twilio_events_job.rb new file mode 100644 index 000000000..cd430a6eb --- /dev/null +++ b/app/jobs/webhooks/twilio_events_job.rb @@ -0,0 +1,8 @@ +class Webhooks::TwilioEventsJob < ApplicationJob + queue_as :low + + def perform(params = {}) + # Process the Twilio webhook event in the background + ::Twilio::IncomingMessageService.new(params: params).perform + end +end diff --git a/spec/controllers/twilio/callbacks_controller_spec.rb b/spec/controllers/twilio/callbacks_controller_spec.rb index bf975be6b..d16acf229 100644 --- a/spec/controllers/twilio/callbacks_controller_spec.rb +++ b/spec/controllers/twilio/callbacks_controller_spec.rb @@ -2,17 +2,27 @@ require 'rails_helper' RSpec.describe 'Twilio::CallbacksController', type: :request do include Rails.application.routes.url_helpers - let(:twilio_service) { instance_double(Twilio::IncomingMessageService) } - before do - allow(Twilio::IncomingMessageService).to receive(:new).and_return(twilio_service) - allow(twilio_service).to receive(:perform) - end + describe 'POST /twilio/callback' do + let(:params) do + { + 'From' => '+1234567890', + 'To' => '+0987654321', + 'Body' => 'Test message', + 'AccountSid' => 'AC123', + 'SmsSid' => 'SM123' + } + end - describe 'GET /twilio/callback' do - it 'calls incoming message service' do - post twilio_callback_index_url, params: {} - expect(twilio_service).to have_received(:perform) + it 'enqueues the Twilio events job' do + expect do + post twilio_callback_index_url, params: params + end.to have_enqueued_job(Webhooks::TwilioEventsJob).with(params) + end + + it 'returns no content status' do + post twilio_callback_index_url, params: params + expect(response).to have_http_status(:no_content) end end end diff --git a/spec/controllers/twilio/delivery_status_controller_spec.rb b/spec/controllers/twilio/delivery_status_controller_spec.rb index 05c236259..fc21f8f94 100644 --- a/spec/controllers/twilio/delivery_status_controller_spec.rb +++ b/spec/controllers/twilio/delivery_status_controller_spec.rb @@ -2,17 +2,25 @@ require 'rails_helper' RSpec.describe 'Twilio::DeliveryStatusController', type: :request do include Rails.application.routes.url_helpers - let(:twilio_service) { instance_double(Twilio::DeliveryStatusService) } - before do - allow(Twilio::DeliveryStatusService).to receive(:new).and_return(twilio_service) - allow(twilio_service).to receive(:perform) - end + describe 'POST /twilio/delivery_status' do + let(:params) do + { + 'MessageSid' => 'SM123', + 'MessageStatus' => 'delivered', + 'AccountSid' => 'AC123' + } + end - describe 'POST /twilio/delivery' do - it 'calls incoming message service' do - post twilio_delivery_status_index_url, params: {} - expect(twilio_service).to have_received(:perform) + it 'enqueues the Twilio delivery status job' do + expect do + post twilio_delivery_status_index_url, params: params + end.to have_enqueued_job(Webhooks::TwilioDeliveryStatusJob).with(params) + end + + it 'returns no content status' do + post twilio_delivery_status_index_url, params: params + expect(response).to have_http_status(:no_content) end end end diff --git a/spec/jobs/webhooks/twilio_delivery_status_job_spec.rb b/spec/jobs/webhooks/twilio_delivery_status_job_spec.rb new file mode 100644 index 000000000..dc94169ae --- /dev/null +++ b/spec/jobs/webhooks/twilio_delivery_status_job_spec.rb @@ -0,0 +1,26 @@ +require 'rails_helper' + +RSpec.describe Webhooks::TwilioDeliveryStatusJob do + subject(:job) { described_class.perform_later(params) } + + let(:params) do + { + 'MessageSid' => 'SM123', + 'MessageStatus' => 'delivered', + 'AccountSid' => 'AC123' + } + end + + it 'queues the job' do + expect { job }.to have_enqueued_job(described_class) + .with(params) + .on_queue('low') + end + + it 'calls the Twilio::DeliveryStatusService' do + service = double + expect(Twilio::DeliveryStatusService).to receive(:new).with(params: params).and_return(service) + expect(service).to receive(:perform) + described_class.new.perform(params) + end +end diff --git a/spec/jobs/webhooks/twilio_events_job_spec.rb b/spec/jobs/webhooks/twilio_events_job_spec.rb new file mode 100644 index 000000000..4eea87d6a --- /dev/null +++ b/spec/jobs/webhooks/twilio_events_job_spec.rb @@ -0,0 +1,28 @@ +require 'rails_helper' + +RSpec.describe Webhooks::TwilioEventsJob do + subject(:job) { described_class.perform_later(params) } + + let(:params) do + { + 'From' => '+1234567890', + 'To' => '+0987654321', + 'Body' => 'Test message', + 'AccountSid' => 'AC123', + 'SmsSid' => 'SM123' + } + end + + it 'queues the job' do + expect { job }.to have_enqueued_job(described_class) + .with(params) + .on_queue('low') + end + + it 'calls the Twilio::IncomingMessageService' do + service = double + expect(Twilio::IncomingMessageService).to receive(:new).with(params: params).and_return(service) + expect(service).to receive(:perform) + described_class.new.perform(params) + end +end