2014-02-05 58 views
0

在这里,我走了!我正在用Ruby on Rails构建一个平台。 我正在使用Resque-Redis来保存一些统计信息,并且发现了一些问题。数据保存两次 - Resque

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

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:对不起,我的英语。

+0

您使用的是什么导轨版本? – BroiSatse

回答

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的事务是原子,所以没有线程这两个语句之间跳转。

+1

但是两个线程都不能有一个未保存的新的StatsApp对象?除非“新”更改为“创建”,否则我认为仍然存在问题? – SteveTurczyn

+0

你说得对,应该创建,没有初始化。答案已更新。 – BroiSatse

+0

嗨,大家好!听起来不错,但是当我尝试去做stat.increment(action)的时候我有一个错误。 '错误: 错误的参数数量(1为3) /home/app/models/stats_app.rb:10:in增量 ' 任何想法为什么? – Luismiv85

0

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

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 

谢谢你们!