Я не знаю, есть ли у вас redis
как часть вашей инфраструктуры, но то, что вы описываете, является условием гонки. Для ее решения вам понадобится мьютекс / блокировка вашего критического пути create_or_update_contact
.
Состояние гонки здесь происходит между двумя асинхронными рабочими / процессами, поэтому вы не можете просто использовать простой ruby mutex / lock. Вам нужен распределенный мьютекс, который использует хранилище / хранитель центрального замка. Это: https://github.com/kenn/redis-mutex должно сделать это за вас, но вам понадобится redis
база данных.
В основном ваш код будет выглядеть примерно так:
class CreateOrUpdateContactWorker
include Sidekiq::Worker
sidekiq_options retry: 2, queue: 'contact_updater', concurrency: 1
sidekiq_retries_exhausted do |msg|
Airbrake.notify(error_message: "Contact update failed", session: { msg: msg })
end
def perform(user_id, changed_fields, update_address = false)
RedisMutex.with_lock("#{user_id}_create_or_update_contact") do
ContactUpdater.create_or_update_contact(user_id, changed_fields, update_address: update_address)
end
end
end
Таким образом, если у вас есть 2 пользовательских обновления для user_id = 1 одновременно, первый, кто получит блокировку / мьютекс с именем 1_create_or_update_contact
, выполнится первым и заблокирует другой вызов до его завершения, а затем начнется второй вызов.
Это решит вашу проблему :) Я думаю, redis
необходим, полезен и полезен. Я не могу придумать ни одного из моих проектов rails без необходимости использовать redis
.