【发布时间】:2018-02-07 01:55:06
【问题描述】:
Sidekiq 建议所有作业都是幂等的(能够多次运行而不会出现问题),因为它不能保证一个作业只会运行一次。
在某些情况下,我无法理解实现这一目标的最佳方式。例如,假设您有下表:
用户 ID 电子邮件 余额
运行的后台作业只是增加了一些余额
def perform(user_id, balance_adjustment)
user = User.find(user_id)
user.balance += balance_adjustment
user.save
end
如果此作业多次运行,则其余额将不正确。这种情况的最佳做法是什么?
如果我考虑一下,我可以想出的一个潜在解决方案是在安排类似的工作之前创建一个记录
PendingBalanceAdjustment 用户身份 平衡调整
当作业运行时,它需要为该用户获取一个锁,这样两个工作人员之间就不会出现竞争条件,然后在释放锁之前需要更新余额并从待处理的余额调整中删除记录.
然后工作看起来像这样?
def perform(user_id, balance_adjustment_id)
user = User.find(user_id)
pba = PendingBalanceAdjustment.where(:balance_adjustment_id => balance_adjustment_id).take
if pba.present?
$redis.lock("#{user_id}/balance_adjustment") do
user.balance += pba.balance_adjustment
user.save
pba.delete
end
end
end
这似乎解决了两个问题
a) 两名同时接受工作的工人之间的竞争条件(尽管您认为 Sidekiq 已经可以保证这一点?) b) 一个作业运行成功后被多次运行
这种模式是一个好的解决方案吗?
【问题讨论】:
标签: ruby-on-rails ruby multithreading sidekiq