繁体   English   中英

Sidekiq:找到最后一份工作

[英]Sidekiq: Find last job

我有两个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字段, 以找出整个过程(加载提要,将其拆分为作业,处理文章)花费了多长时间。

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. 提要可能会很长(〜800,000篇文章),并且在您只需要最后一个时,更新值800,000次似乎是很多不必要的工作。 有什么主意如何找出最后一个工作,而仅更新此工作的end_time字段?

对于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

这是Sidekiq Pro的“ 批处理”功能解决的问题。 您创建了一组作业,当它们全部完成时,它将调用您的代码。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM