我在我的rails应用程序中使用Sidekiq一次排队50k +作业。我们的游泳池大小设置为9.
这些工作都是相关的,并且做同样的事情。我们有另一个模型,它有一个计数器。在每个作业期间,我们检查该模型是否具有值大于200的列。如果它大于200,我们创建该模型的另一个实例,其值为0并继续作业。但是,由于我们一次运行9个作业,因此所有9个作业同时读取该列的值大于200,并且所有作业都创建新实例,这是不正确的。
解决此问题的最佳方法是什么?我们基本上希望所有工作都能从最新的价值中读取。
答案 0 :(得分:1)
我无法发布任何特定代码,因为它在很大程度上取决于您的数据库类型和设置,但您应该尝试数据库锁定。
工作人员在阅读表时应将其锁定,直到完成创建值为0的新记录。您应该锁定表以供读取,以便其他工作人员需要等到这一个工作人员完成。也可以锁定单独的行,但我不知道它是否适用于您的情况。
答案 1 :(得分:1)
假设您的模型被称为Counter
。
首先,找到/创建一个合适的计数器:
counter = Counter.where('count < 200').first_or_create ...
(注意:这不是原子的!如果你不能有超过1个活跃的计数器,那么请看:
Race conditions in Rails first_or_create和
How do I avoid a race condition in my Rails app?)
接下来,尝试在数据库中以原子方式递增它:
success =
Counter.where(id: counter.id)
.where('count < 200')
.update_all('count = count + 1')
如果有效,success == 1
则为success == 0
。如果有效,请使用计数器,否则请重试。
答案 2 :(得分:1)
Redis更适合此类操作,您可以通过Sidekiq的Redis连接轻松访问它。
value = Sidekiq.redis { |c| c.incr("my-counter") }
if value % 200 == 0
# create new instance
end
也许这样的事情对你有用。