ActiveJob / Resque脏读。事务隔离级别

时间:2016-08-11 14:52:22

标签: ruby-on-rails ruby-on-rails-4 resque

我有几个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

1 个答案:

答案 0 :(得分:1)

第一个选项是使用锁定optimisticpessimistic)。文档解释了它们之间的差异,您可以选择适合您情况的文档。此外,如果您使用乐观锁定,那么来自文档的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)方法使代码更具可读性。