【问题标题】:Datas are saved twice - Resque数据保存两次 - Resque
【发布时间】:2014-02-06 21:06:07
【问题描述】:

我来了!我正在使用 Ruby on Rails 构建一个平台。 我正在使用 Resque - Redis 来保存一些统计信息,但我发现了一些问题。

我必须保存应用程序每天执行操作的次数,例如,如果应用程序已运行,我必须保存该应用程序在当天运行。问题是一个应用程序可以被多个用户同时使用,现在问题来了。

unless stat = self.where(app_id: app_id, day: fire_at.to_date).first
  stat = StatsApp.new(app_id: app_id, day: fire_at.to_date)
end

stat.increment(action)

逻辑:如果是一天中的第一次,则创建一个新的寄存器,如果不是,则增加这一天的动作。

有时,我可以看到一个应用程序被保存了两次,因为我有很多进程在队列中并且我有 10 个工作人员正在运行。

有人可以帮我避免这种情况吗?

PS:对不起我的英语。

【问题讨论】:

  • 你用的是什么版本的rails?

标签: ruby-on-rails ruby redis resque worker


【解决方案1】:

出现这种情况的原因是线程并发:

Thread 1: stat = self.where(app_id: app_id, day: fire_at.to_date).first   #=> false
Thread 2: stat = self.where(app_id: app_id, day: fire_at.to_date).first   #=> false
Thread 2: stat = StatsApp.new(app_id: app_id, day: fire_at.to_date)
Thread 1: stat = StatsApp.new(app_id: app_id, day: fire_at.to_date)

为避免这种情况,您需要使用 ActiveRecord 事务:

stat = self.transaction do
  self.where(app_id: app_id, day: fire_at.to_date).first || StatsApp.create(app_id: app_id, day: fire_at.to_date)
end

ActiveRecord 事务是原子的,因此没有线程会在这两个语句之间跳转。

【讨论】:

  • 但是两个线程不能都有一个未保存的新 StatsApp 对象吗?除非将“新”改为“创建”,否则我认为还会有问题?
  • 你说得对,应该被创建,而不是初始化。答案已更新。
  • 大家好!听起来不错,但是当我尝试执行 stat.increment(action) 时出现错误。 Error: wrong number of arguments (1 for 3) /home/app/models/stats_app.rb:10:in increment 任何想法为什么?
  • 如果你给我们看increment方法的代码会更容易。
  • @BroiSatse 你对我的回答是正确的! :(我决定躺下喝杯茶。
【解决方案2】:

好吧,几个小时后我找到了解决方案!

StatsApp.transaction do

    stat = self.where(app_id: app_id, day: fire_at.to_date).lock(true).first || StatsApp.create(app_id: app_id, day: fire_at.to_date)

    stat.increment(action)
    stat.save

end

谢谢大家!!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-16
    • 1970-01-01
    • 1970-01-01
    • 2017-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多