我有两个Sidekiq工作。第一个加载JSON中的文章提要并将其拆分为多个作业。它还会创建一个日志并存储start_time
。
class LoadFeed
include Sidekiq::Worker
def perform url
log = Log.create! start_time: Time.now, url: url
articles = load_feed(url) # this one loads the feed
articles.each do |article|
ProcessArticle.perform_async(article, log.id)
end
end
end
第二个作业处理文章并更新以前创建的日志的end_time
字段,以查明整个过程(加载Feed,将其拆分为作业,处理文章)花了多长时间
class ProcessArticle
include Sidekiq::Worker
def perform data, log_id
process(data)
Log.find(log_id).update_attribute(:end_time, Time.now)
end
end
但现在我遇到了一些问题:
Log.find(log_id).update_attribute(:end_time, Time.now)
不是原子的,由于作业的异步行为,这可能会导致end_time
值不正确。有没有办法用当前时间对MySQL中的datetime
字段进行原子更新?- 饲料可以变得很长(约80万篇文章)并且当你需要最后一篇文章时更新值800k次似乎是很多不必要的工作。 任何想法如何找出哪一个是上一份工作,只更新此职位中的
醇>end_time
字段?
答案 0 :(得分:1)
对于1)你可以用少一个查询进行更新,让MySQL找到时间:
Log.where(id: log_id).update_all('end_time = now()')
对于2)解决此问题的一种方法是仅在所有文章都已处理后更新您的结束时间。例如,通过拥有一个可以查询的布尔值。这不会减少查询次数,但肯定会有更好的性能。
if feed.articles.needs_processing.none?
Log.where(id: log_id).update_all('end_time = now()')
end
答案 1 :(得分:0)
这是Sidekiq Pro Batch功能解决的问题。您创建了一组作业,它们在完成后调用您的代码。
class LoadFeed
include Sidekiq::Worker
def on_success(status, options)
Log.find(options['log_id']).update_attribute(:end_time, Time.now)
end
def perform url
log = Log.create! start_time: Time.now, url: url
articles = load_feed(url) # this one loads the feed
batch = Sidekiq::Batch.new
batch.on(:success, self.class, 'log_id' => log.id)
batch.jobs do
articles.each do |article|
ProcessArticle.perform_async(article, log.id)
end
end
end
end