Skip to content

Commit

Permalink
Fixing race condition
Browse files Browse the repository at this point in the history
  • Loading branch information
caiosba committed Oct 26, 2023
1 parent 33d4395 commit f96329e
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 10 deletions.
2 changes: 1 addition & 1 deletion app/models/bot/smooch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1075,7 +1075,7 @@ def self.refresh_smooch_menu_timeout(message, app_id)
uid = message['authorId']
time = Time.now.to_f
Rails.cache.write("smooch:last_message_from_user:#{uid}", time)
self.delay_for(15.minutes, { queue: 'smooch' }).timeout_smooch_menu(time, message, app_id, RequestStore.store[:smooch_bot_provider])
self.delay_for(5.minutes, { queue: 'smooch' }).timeout_smooch_menu(time, message, app_id, RequestStore.store[:smooch_bot_provider])
end

def self.timeout_smooch_menu(time, message, app_id, provider)
Expand Down
15 changes: 10 additions & 5 deletions app/models/concerns/smooch_messages.rb
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ def handle_bundle_messages(type, list, last, app_id, annotated, send_message = t
if ['timeout_requests', 'menu_options_requests', 'resource_requests', 'relevant_search_result_requests', 'timeout_search_requests'].include?(type)
key = "smooch:banned:#{bundle['authorId']}"
if Rails.cache.read(key).nil?
[annotated].flatten.uniq.each { |a| self.save_message_later(bundle, app_id, type, a) }
[annotated].flatten.uniq.each_with_index { |a, i| self.save_message_later(bundle, app_id, type, a, i * 10) }
end
end
end
Expand Down Expand Up @@ -317,12 +317,12 @@ def supported_message?(message)
ret
end

def save_message_later(message, app_id, request_type = 'default_requests', annotated = nil)
def save_message_later(message, app_id, request_type = 'default_requests', annotated = nil, interval = 0)
mapping = { 'siege' => 'siege' }
queue = RequestStore.store[:smooch_bot_queue].to_s
queue = queue.blank? ? 'smooch' : (mapping[queue] || 'smooch')
type = (message['type'] == 'text' && !message['text'][/https?:\/\/[^\s]+/, 0].blank?) ? 'link' : message['type']
SmoochWorker.set(queue: queue).perform_in(1.second, message.to_json, type, app_id, request_type, YAML.dump(annotated))
SmoochWorker.set(queue: queue).perform_in(1.second + interval.seconds, message.to_json, type, app_id, request_type, YAML.dump(annotated))
end

def default_archived_flag
Expand Down Expand Up @@ -370,8 +370,9 @@ def create_smooch_request(annotated, message, app_id, author)
fields = { smooch_data: message.merge({ app_id: app_id }).to_json }
result = self.smooch_api_get_messages(app_id, message['authorId'])
fields[:smooch_conversation_id] = result.conversation.id unless result.nil? || result.conversation.nil?
fields[:smooch_message_id] = message['_id']
self.create_smooch_annotations(annotated, author, fields)
# update channel values for ProjectMedia items
# Update channel values for ProjectMedia items
if annotated.class.name == 'ProjectMedia'
channel_value = self.get_smooch_channel(message)
unless channel_value.blank?
Expand Down Expand Up @@ -407,7 +408,11 @@ def create_smooch_annotations(annotated, author, fields, attach_to = false)
a.skip_notifications = true
a.disable_es_callbacks = Rails.env.to_s == 'test'
a.set_fields = fields.to_json
a.save!
begin
a.save!
rescue ActiveRecord::RecordNotUnique
# Don't save a duplicate request
end
User.current = current_user
end

Expand Down
11 changes: 7 additions & 4 deletions app/models/concerns/smooch_search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -247,15 +247,16 @@ def send_search_results_to_whatsapp_user(uid, reports, app_id)
# Expires after the time to give feedback is expired
Rails.cache.write("smooch:user_search_bundle:#{uid}:#{search_id}", self.list_of_bundled_messages_from_user(uid), expires_in: 20.minutes)
self.clear_user_bundled_messages(uid)
reports.each do |report|
reports.each_with_index do |report, i|
text = report.report_design_text if report.report_design_field_value('use_text_message')
image_url = report.report_design_image_url if report.report_design_field_value('use_visual_card')
options = [{
value: { project_media_id: report.annotated_id, keyword: 'search_result_is_relevant', search_id: search_id }.to_json,
value: { project_media_id: report.annotated_id, keyword: 'search_result_is_relevant', search_id: search_id, index: i }.to_json,
label: '👍'
}]
self.send_message_to_user_with_buttons(uid, text || '-', options, image_url, 'search_result') # "text" is mandatory for WhatsApp interactive messages
self.delay_for(15.minutes, { queue: 'smooch_priority' }).timeout_if_no_feedback_is_given_to_search_result(app_id, uid, search_id, report.annotated_id)
# Schedule each timeout with some interval between them just to avoid race conditions that could create duplicate media
self.delay_for((5 + i).minutes, { queue: 'smooch_priority' }).timeout_if_no_feedback_is_given_to_search_result(app_id, uid, search_id, report.annotated_id)
end
end

Expand Down Expand Up @@ -313,8 +314,10 @@ def search_result_button_click_callback(message, uid, app_id, workflow, language
result = ProjectMedia.find(payload['project_media_id'])
bundle = Rails.cache.read("smooch:user_search_bundle:#{uid}:#{payload['search_id']}").to_a
unless bundle.empty?
# Give some interval just to avoid race conditions if the user gives feedback too fast
interval = payload['index'].to_i * 10
Rails.cache.write("smooch:user_search_bundle:#{uid}:#{payload['search_id']}:#{result.id}", Time.now.to_i) # Store that the user has given feedback to this search result
self.delay_for(1.seconds, { queue: 'smooch', retry: false }).bundle_messages(uid, message['_id'], app_id, 'relevant_search_result_requests', [result], true, bundle)
self.delay_for((interval + 1).seconds, { queue: 'smooch', retry: false }).bundle_messages(uid, message['_id'], app_id, 'relevant_search_result_requests', [result], true, bundle)
self.send_final_message_to_user(uid, self.get_custom_string('search_result_is_relevant', language), workflow, language)
end
end
Expand Down
11 changes: 11 additions & 0 deletions db/migrate/20231026162554_add_smooch_message_id_field.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class AddSmoochMessageIdField < ActiveRecord::Migration[6.1]
require 'sample_data'
include SampleData

def change
at = DynamicAnnotation::AnnotationType.where(annotation_type: 'smooch').last
ft = DynamicAnnotation::FieldType.where(field_type: 'text').last || create_field_type(field_type: 'text', label: 'Text')
create_field_instance annotation_type_object: at, name: 'smooch_message_id', label: 'Message Id', field_type_object: ft, optional: true
execute %{CREATE UNIQUE INDEX smooch_request_message_id_unique_id ON dynamic_annotation_fields (value) WHERE field_name = 'smooch_message_id' AND value <> '' AND value <> '""'}
end
end

0 comments on commit f96329e

Please sign in to comment.