diff --git a/app/models/draft.rb b/app/models/draft.rb index 4f7a03711f3..aee066c0e27 100644 --- a/app/models/draft.rb +++ b/app/models/draft.rb @@ -7,7 +7,7 @@ class Draft < ActiveRecord::Base class OutOfSequence < StandardError; end - def self.set(user, key, sequence, data, owner = nil) + def self.set(user, key, sequence, data, owner = nil, retry_not_unique: true) if SiteSetting.backup_drafts_to_pm_length > 0 && SiteSetting.backup_drafts_to_pm_length < data.length backup_draft(user, key, sequence, data) end @@ -65,13 +65,24 @@ class Draft < ActiveRecord::Base elsif sequence != current_sequence raise Draft::OutOfSequence else - Draft.create!( - user_id: user.id, - draft_key: key, - data: data, - sequence: sequence, - owner: owner - ) + begin + Draft.create!( + user_id: user.id, + draft_key: key, + data: data, + sequence: sequence, + owner: owner + ) + rescue ActiveRecord::RecordNotUnique => e + # we need this to be fast and with minimal locking, in some cases we can have a race condition + # around 2 controller actions calling for draft creation at the exact same time + # to avoid complex locking and a distributed mutex, since this is so rare, simply add a single retry + if retry_not_unique + set(user, key, sequence, data, owenr, retry_not_unique: false) + else + raise e + end + end end sequence