Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何防止Sidekiq并行修改数据库_Ruby On Rails_Multithreading_Sidekiq - Fatal编程技术网

Ruby on rails 如何防止Sidekiq并行修改数据库

Ruby on rails 如何防止Sidekiq并行修改数据库,ruby-on-rails,multithreading,sidekiq,Ruby On Rails,Multithreading,Sidekiq,我有一个工作人员试图根据某些条件为照片找到匹配项。每一张照片都有一个独特的匹配。我编写了如下代码: 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

我有一个工作人员试图根据某些条件为照片找到匹配项。每一张照片都有一个独特的匹配。我编写了如下代码:

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获取第一个传递条件的模型对象,然后更改
匹配
,将其从未来的workers匹配列表中排除

问题是,当几个工作人员同时执行操作时,他们都会得到相同的
匹配列表,从而修改相同的实体。但我需要一个独特的匹配每一张照片

我怎样才能解决这个问题

其他信息:

问:我为什么使用工人

A:如果找不到匹配项,我需要稍后重试

问:为什么我要将Sidekiq与多个线程一起使用

我需要尽快处理照片

也许我可以在每一个匹配开始时计算出当前活跃的工作人员的数量,并进行第n个匹配,而不是第一个匹配。但那个解决方案有点臭,不是吗

更新:


附加问题:我可以用一些关于ActiveRecord锁定的东西来解决这个问题吗?我对锁和所有这些东西都不太熟悉。

解决问题的一个非常简单的方法是分配工作量,这样工人就不会相互干扰


如果您有两个工人,您可以对他们进行编号,并对id
photo.id%2
进行模运算。这样,结果只能得到0和1。编号为0的工人仅在其批次上工作,编号为1的工人在另一批次上工作。通过增加模,您可以增加所需的工人数量。

实际代码要复杂得多,并且对于每个照片,可能的匹配的真实集可能会有所不同。所以它们是不相等的,我不能为每个工人把这个列表分成几个部分。但是谢谢你提出的一个有趣的建议!另一个简单的解决方案是用匹配项持久化一个工人id,这样他们就可以这样离开。通常做这种事情的方法是让一个主工人向其他工人发出匹配项。因此,您只有一个工作人员负责查找匹配项,其余的工作人员则在做一些艰苦的工作,并且只分配了一个匹配项。您可以为此下拉到原始SQL:
updatephotos SET match\u id=?其中id=?并且匹配id为空
。这样,只有第一次更新才能找到并更新记录。假设一个简单的条件,您可以使用照片ID为每个条件保留一个redis列表/设置,然后使用
BRPOP
RPOP
获取匹配的ID,并确保此ID永远不会被重用。编辑:您可能还可以处理包含所有ID的列表/集合,以确保它不会在redis中重用