Sidekiq:找到上一份工作

时间:2016-01-23 10:15:04

标签: mysql ruby sidekiq

我有两个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

但现在我遇到了一些问题:

  
      
  1. Log.find(log_id).update_attribute(:end_time, Time.now)不是原子的,由于作业的异步行为,这可能会导致end_time值不正确。有没有办法用当前时间对MySQL中的datetime字段进行原子更新?
  2.   
  3. 饲料可以变得很长(约80万篇文章)并且当你需要最后一篇文章时更新值800k次似乎是很多不必要的工作。 任何想法如何找出哪一个是上一份工作,只更新此职位中的end_time字段?
  4.   

2 个答案:

答案 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