fix: Add delay to instagram/messenger echo events to prevent duplicate messages (#12032)
- Add 2-second delay to Facebook Messenger echo event processing to prevent race condition - Add 2-second delay to Instagram echo event processing for consistency - Prevent duplicate messages when echo events arrive before send message API completes processing --------- Co-authored-by: Sojan Jose <sojan@pepalo.com>
This commit is contained in:
@@ -4,7 +4,16 @@ class Webhooks::InstagramController < ActionController::API
|
||||
def events
|
||||
Rails.logger.info('Instagram webhook received events')
|
||||
if params['object'].casecmp('instagram').zero?
|
||||
::Webhooks::InstagramEventsJob.perform_later(params.to_unsafe_hash[:entry])
|
||||
entry_params = params.to_unsafe_hash[:entry]
|
||||
|
||||
if contains_echo_event?(entry_params)
|
||||
# Add delay to prevent race condition where echo arrives before send message API completes
|
||||
# This avoids duplicate messages when echo comes early during API processing
|
||||
::Webhooks::InstagramEventsJob.set(wait: 2.seconds).perform_later(entry_params)
|
||||
else
|
||||
::Webhooks::InstagramEventsJob.perform_later(entry_params)
|
||||
end
|
||||
|
||||
render json: :ok
|
||||
else
|
||||
Rails.logger.warn("Message is not received from the instagram webhook event: #{params['object']}")
|
||||
@@ -14,6 +23,16 @@ class Webhooks::InstagramController < ActionController::API
|
||||
|
||||
private
|
||||
|
||||
def contains_echo_event?(entry_params)
|
||||
return false unless entry_params.is_a?(Array)
|
||||
|
||||
entry_params.any? do |entry|
|
||||
# Check messaging array for echo events
|
||||
messaging_events = entry[:messaging] || []
|
||||
messaging_events.any? { |messaging| messaging.dig(:message, :is_echo).present? }
|
||||
end
|
||||
end
|
||||
|
||||
def valid_token?(token)
|
||||
# Validates against both IG_VERIFY_TOKEN (Instagram channel via Facebook page) and
|
||||
# INSTAGRAM_VERIFY_TOKEN (Instagram channel via direct Instagram login)
|
||||
|
||||
@@ -39,6 +39,8 @@ Rails.application.reloader.to_prepare do
|
||||
end
|
||||
|
||||
Facebook::Messenger::Bot.on :message_echo do |message|
|
||||
Webhooks::FacebookEventsJob.perform_later(message.to_json)
|
||||
# Add delay to prevent race condition where echo arrives before send message API completes
|
||||
# This avoids duplicate messages when echo comes early during API processing
|
||||
Webhooks::FacebookEventsJob.set(wait: 2.seconds).perform_later(message.to_json)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,5 +33,21 @@ RSpec.describe 'Webhooks::InstagramController', type: :request do
|
||||
post '/webhooks/instagram', params: instagram_params
|
||||
expect(response).to have_http_status(:success)
|
||||
end
|
||||
|
||||
context 'when processing echo events' do
|
||||
let!(:echo_params) { build(:instagram_story_mention_event_with_echo).with_indifferent_access }
|
||||
|
||||
it 'delays processing for echo events by 2 seconds' do
|
||||
job_double = class_double(Webhooks::InstagramEventsJob)
|
||||
allow(Webhooks::InstagramEventsJob).to receive(:set).with(wait: 2.seconds).and_return(job_double)
|
||||
allow(job_double).to receive(:perform_later)
|
||||
|
||||
instagram_params = echo_params.merge(object: 'instagram')
|
||||
post '/webhooks/instagram', params: instagram_params
|
||||
expect(response).to have_http_status(:success)
|
||||
expect(Webhooks::InstagramEventsJob).to have_received(:set).with(wait: 2.seconds)
|
||||
expect(job_double).to have_received(:perform_later)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user