chore: Move Whatsapp template sync to cron (#4858)

syncing WhatsApp templates job is moved to a cron job for a better user experience. The Templates are synced at 15-minute intervals now.
This commit is contained in:
Sojan Jose 2022-06-14 23:46:36 +05:30 committed by GitHub
parent 1bb0371c1d
commit fdcaed75f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 88 additions and 9 deletions

View file

@ -0,0 +1,7 @@
class Channels::Whatsapp::TemplatesSyncJob < ApplicationJob
queue_as :low
def perform(whatsapp_channel)
whatsapp_channel.sync_templates
end
end

View file

@ -0,0 +1,12 @@
class Channels::Whatsapp::TemplatesSyncSchedulerJob < ApplicationJob
queue_as :low
def perform
Channel::Whatsapp.where('message_templates_last_updated <= ? OR message_templates_last_updated IS NULL',
15.minutes.ago).find_in_batches do |channels_batch|
channels_batch.each do |channel|
Channels::Whatsapp::TemplatesSyncJob.perform_later(channel)
end
end
end
end

View file

@ -12,5 +12,8 @@ class TriggerScheduledItemsJob < ApplicationJob
# Job to auto-resolve conversations # Job to auto-resolve conversations
Account::ConversationsResolutionSchedulerJob.perform_later Account::ConversationsResolutionSchedulerJob.perform_later
# Job to sync whatsapp templates
Channels::Whatsapp::TemplatesSyncSchedulerJob.perform_later
end end
end end

View file

@ -25,6 +25,7 @@ class Channel::Whatsapp < ApplicationRecord
validates :phone_number, presence: true, uniqueness: true validates :phone_number, presence: true, uniqueness: true
before_save :validate_provider_config before_save :validate_provider_config
after_create :sync_templates
def name def name
'Whatsapp' 'Whatsapp'
@ -62,10 +63,6 @@ class Channel::Whatsapp < ApplicationRecord
end end
def sync_templates def sync_templates
# to prevent too many api calls
last_updated = message_templates_last_updated || 1.day.ago
return if Time.current < (last_updated + 12.hours)
response = HTTParty.get("#{api_base_path}/configs/templates", headers: api_headers) response = HTTParty.get("#{api_base_path}/configs/templates", headers: api_headers)
update(message_templates: response['waba_templates'], message_templates_last_updated: Time.now.utc) if response.success? update(message_templates: response['waba_templates'], message_templates_last_updated: Time.now.utc) if response.success?
end end

View file

@ -15,7 +15,6 @@ class Whatsapp::SendOnWhatsappService < Base::SendOnChannelService
end end
def send_template_message def send_template_message
channel.sync_templates
name, namespace, lang_code, processed_parameters = processable_channel_message_template name, namespace, lang_code, processed_parameters = processable_channel_message_template
return if name.blank? return if name.blank?

View file

@ -34,6 +34,15 @@ FactoryBot.define do
end end
message_templates_last_updated { Time.now.utc } message_templates_last_updated { Time.now.utc }
transient do
sync_templates { true }
end
before(:create) do |channel_whatsapp, options|
# since factory already has the required message templates, we just need to bypass it getting updated
channel_whatsapp.define_singleton_method(:sync_templates) { return } unless options.sync_templates
end
after(:create) do |channel_whatsapp| after(:create) do |channel_whatsapp|
create(:inbox, channel: channel_whatsapp, account: channel_whatsapp.account) create(:inbox, channel: channel_whatsapp, account: channel_whatsapp.account)
end end

View file

@ -0,0 +1,20 @@
require 'rails_helper'
RSpec.describe Channels::Whatsapp::TemplatesSyncJob, type: :job do
let(:channel_whatsapp) { create(:channel_whatsapp, sync_templates: false) }
it 'enqueues the job' do
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook')
expect { described_class.perform_later(channel_whatsapp) }.to have_enqueued_job(described_class)
.on_queue('low')
end
context 'when called' do
it 'calls sync_templates' do
whatsapp_channel = double
allow(whatsapp_channel).to receive(:sync_templates).and_return(true)
expect(whatsapp_channel).to receive(:sync_templates)
described_class.perform_now(whatsapp_channel)
end
end
end

View file

@ -0,0 +1,27 @@
require 'rails_helper'
RSpec.describe Channels::Whatsapp::TemplatesSyncSchedulerJob, type: :job do
it 'enqueues the job' do
expect { described_class.perform_later }.to have_enqueued_job(described_class)
.on_queue('low')
end
context 'when called' do
it 'schedules templates_sync_jobs for channels where templates need to be updated' do
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook')
non_synced = create(:channel_whatsapp, sync_templates: false, message_templates_last_updated: nil)
synced_recently = create(:channel_whatsapp, sync_templates: false, message_templates_last_updated: Time.zone.now)
synced_old = create(:channel_whatsapp, sync_templates: false, message_templates_last_updated: 16.minutes.ago)
described_class.perform_now
expect(Channels::Whatsapp::TemplatesSyncJob).not_to(
have_been_enqueued.with(synced_recently).on_queue('low')
)
expect(Channels::Whatsapp::TemplatesSyncJob).to(
have_been_enqueued.with(synced_old).on_queue('low')
)
expect(Channels::Whatsapp::TemplatesSyncJob).to(
have_been_enqueued.with(non_synced).on_queue('low')
)
end
end
end

View file

@ -66,9 +66,9 @@ RSpec.describe SendReplyJob, type: :job do
described_class.perform_now(message.id) described_class.perform_now(message.id)
end end
it 'calls ::Whatsapp:SendOnWhatsappService when its line message' do it 'calls ::Whatsapp:SendOnWhatsappService when its whatsapp message' do
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook') stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook')
whatsapp_channel = create(:channel_whatsapp) whatsapp_channel = create(:channel_whatsapp, sync_templates: false)
message = create(:message, conversation: create(:conversation, inbox: whatsapp_channel.inbox)) message = create(:message, conversation: create(:conversation, inbox: whatsapp_channel.inbox))
allow(::Whatsapp::SendOnWhatsappService).to receive(:new).with(message: message).and_return(process_service) allow(::Whatsapp::SendOnWhatsappService).to receive(:new).with(message: message).and_return(process_service)
expect(::Whatsapp::SendOnWhatsappService).to receive(:new).with(message: message) expect(::Whatsapp::SendOnWhatsappService).to receive(:new).with(message: message)

View file

@ -30,5 +30,10 @@ RSpec.describe TriggerScheduledItemsJob, type: :job do
expect(Account::ConversationsResolutionSchedulerJob).to receive(:perform_later).once expect(Account::ConversationsResolutionSchedulerJob).to receive(:perform_later).once
described_class.perform_now described_class.perform_now
end end
it 'triggers Channels::Whatsapp::TemplatesSyncSchedulerJob' do
expect(Channels::Whatsapp::TemplatesSyncSchedulerJob).to receive(:perform_later).once
described_class.perform_now
end
end end
end end

View file

@ -6,7 +6,7 @@ describe Whatsapp::IncomingMessageService do
stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook') stub_request(:post, 'https://waba.360dialog.io/v1/configs/webhook')
end end
let!(:whatsapp_channel) { create(:channel_whatsapp) } let!(:whatsapp_channel) { create(:channel_whatsapp, sync_templates: false) }
context 'when valid text message params' do context 'when valid text message params' do
it 'creates appropriate conversations, message and contacts' do it 'creates appropriate conversations, message and contacts' do

View file

@ -15,7 +15,7 @@ describe Whatsapp::SendOnWhatsappService do
context 'when a valid message' do context 'when a valid message' do
let(:whatsapp_request) { double } let(:whatsapp_request) { double }
let!(:whatsapp_channel) { create(:channel_whatsapp) } let!(:whatsapp_channel) { create(:channel_whatsapp, sync_templates: false) }
let!(:contact_inbox) { create(:contact_inbox, inbox: whatsapp_channel.inbox, source_id: '123456789') } let!(:contact_inbox) { create(:contact_inbox, inbox: whatsapp_channel.inbox, source_id: '123456789') }
let!(:conversation) { create(:conversation, contact_inbox: contact_inbox, inbox: whatsapp_channel.inbox) } let!(:conversation) { create(:conversation, contact_inbox: contact_inbox, inbox: whatsapp_channel.inbox) }