我有一名工作人员试图根据某些条件找到照片匹配。每张照片都有一个独特的匹配。我编写了这样的代码:
class PhotoDeliveryWorker
include Sidekiq::Worker
def perform(photo_id)
photo = Photo.find(photo_id)
unless photo.match
matches = Photo.where(some_condition: "some_value")
match = matches.first
if match
# Do something to photo
photo.match = match
if photo.save
match.some_condition = "another_value"
else
schedule photo_id
end
else
# Couldn't find a match
schedule photo_id
end
end
end
private
def schedule(photo_id)
PhotoDeliveryWorker.perform_in 1.hours, photo_id
end
end
如您所见,worker获取第一个传递条件的模型对象,然后更改match
以将其从将来的工作者匹配列表中排除。
问题是当一些工作人员一次执行时,他们都获得相同的matches
列表,因此修改了同一个实体。但我需要为每张照片添加一个独特的匹配。
我该如何解决?
其他信息:
问:我为什么要雇佣工人?答:如果我找不到匹配项,我需要稍后重试。
问:为什么我使用Sidekiq多线程?
答:我需要尽可能快地处理照片。
可能我可以在每个人的开头得到当前活跃工人的数量,然后取第一个而不是第一个。但那个解决方案闻起来有点味道,不是吗?
更新
其他问题:我可以使用ActiveRecord锁定这个问题吗?我对with_lock
以及所有这些东西都不是很熟悉。
答案 0 :(得分:0)
解决问题的一个非常简单的方法就是分割工作量,这样工人就不会互相干扰。
如果您有2名工作人员,则可以为他们编号,并在ID photo.id % 2
上执行模数。这样你只得到0和1。数字0的工人只能在他的批次上工作,另一名工人的编号为1。通过增加模数,你可以达到你想要的任何数量的工人。