Это классическое состояние гонки.Обратите внимание, что "Sidekiq является многопоточным, поэтому ваши рабочие должны быть поточно-ориентированными." .Все ваши работники работают параллельно, и никто из них изначально не находит соответствующую запись в where
и заканчивает тем, что создает новую запись со счетом 1.
Я советую вместо этого создать / найти запись заранее и отправитьэто идентификатор для увеличения значения count
.Хотя я не уверен, почему вы используете Sidekiq для разгрузки базовой операции UPDATE
.
class User < ApplicationRecord
after_commit :record, on: :create
def record
record = Record.create_with(count: 0).find_by(some_conditions)
SomeWorker.perform_async(record.id)
end
end
class SomeWorker
include Sidekiq::Worker
def perform(id)
Record.find(id).increment!(:count)
end
end
Также обратите внимание, что increment!
также не подходит для параллелизма, но он должен работать в вашем случае.
a = Record.first #<Record id: 1, count: 1>
b = Record.first #<Record id: 1, count: 1>
a.increment!(:count) #<Record id: 1, count: 2>
b.increment!(:count) #<Record id: 1, count: 2> ## SHOULD BE 3
b.reload #<Record id: 1, count: 3> It's actually three, but object was stale on update.
SQL запускаетзапрос, ниже которого отображается значение последнего установленного значения.
UPDATE `records` SET `count` = COALESCE(`parent_id`, 0) + 1 WHERE `records`.`id` = 1