我有几个Resque工作者用于同一个实体(User)。处理成功后,应减少call_left
属性。
它与perform_now
(因此)完美配合,但使用perform_later
(并行)产生不可预测的结果。在日志中,提交具有相同数量的calls_left
。
我尝试使用reload
方法,甚至设置了最高的隔离级别。但仍有这个问题。
如何解决?
class DataProcessJob < ActiveJob::Base
queue_as :default
def perform(user_id, profile_id)
User.transaction(isolation: :serializable) do
user = User.find(user_id).reload
user.data_process(profile_id)
user.update(calls_left: user.calls_left-1)
end
end
end
答案 0 :(得分:1)
第一个选项是使用锁定(optimistic或pessimistic)。文档解释了它们之间的差异,您可以选择适合您情况的文档。此外,如果您使用乐观锁定,那么来自文档的here is a relevant code snippet可能对您有所帮助。
def with_optimistic_retry
begin
yield
rescue ActiveRecord::StaleObjectError
begin
# Reload lock_version in particular.
reload
rescue ActiveRecord::RecordNotFound
# If the record is gone there is nothing to do.
else
retry
end
end
end
第二个选项是使用原始SQL字符串查询增加calls_left
字段。底层数据库将处理原子更新。
最后但并非最不重要的是,您可以使用decrement!(:calls_left)
方法使代码更具可读性。