DelayedJob breaking验证ActiveRecord中的唯一约束

DelayedJob breaking验证ActiveRecord中的唯一约束,activerecord,delayed-job,race-condition,Activerecord,Delayed Job,Race Condition,这很简单,我正在运行一个能找到齿轮的爬虫程序。COG可以属于一个小部件。有时它会发现一堆齿轮,它们都应该属于同一个小部件。在Cog模型中,它运行: # Find or create widget match = Widget.where("name ILIKE (?)", name).first match = Widget.create(name: name) unless match 所有并行运行的延迟作业基本上如下所示: - CREATE Cog, name: "cog1", (Widg

这很简单,我正在运行一个能找到齿轮的爬虫程序。COG可以属于一个小部件。有时它会发现一堆齿轮,它们都应该属于同一个小部件。在Cog模型中,它运行:

# Find or create widget
match = Widget.where("name ILIKE (?)", name).first
match = Widget.create(name: name) unless match
所有并行运行的延迟作业基本上如下所示:

- CREATE Cog, name: "cog1", (Widget, name: "Foo")
- CREATE Cog, name: "cog2", (Widget, name: "Foo")
- CREATE Cog, name: "cog3", (Widget, name: "Foo")
- CREATE Cog, name: "cog4", (Widget, name: "Foo")
这是不可避免的,但我认为将由上面的匹配代码处理。我在小部件模型中也有这样的功能:

validates :name, presence: true, uniqueness: true

不幸的是,由于4个DelayedJob Worker在4个内核上运行,这些作业完全同时运行,导致尽管进行了这两项检查,仍要创建多个小部件。如何在创建小部件时防止竞争条件,以避免重复?

由于唯一性检查和插入是单独执行的,因此存在竞争条件。您需要一个索引来强制唯一性约束


文档提到了这一点:

数据库索引将解决创建重复记录的问题,但它们将引发错误,因为代码仍将在同一时间运行,并且只有数据库将阻止插入。我想要一个应用程序级的解决方案,而不是数据库级的。也许是ActiveRecord交易?