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:
Muhsin Keloth
2025-07-24 21:11:02 +04:00
committed by GitHub
parent 8262123481
commit 87313ecc35
3 changed files with 39 additions and 2 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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