如何确定一组Resque工作是否已完成?

时间:2013-12-10 17:19:21

标签: ruby-on-rails resque jobs

我有以下代码:

[23, 45, 69, 20].each do |page_id|
  Resque.enqueue(ProcessPage, page_id)
end

我想知道所有这些工作何时完成处理以通过电子邮件通知用户。我的第一次尝试是在工作的最后通知用户,但这对每项工作都是单独的。

我找到了这个宝石resque-status,基本上你可以这样做:

job_ids = []
[23, 45, 69, 20].each do |page_id|
  job_ids << ProcessPage.create(page_id)
end

然后您可以通过执行以下操作来检查作业的状态:

status = Resque::Plugins::Status::Hash.get(job_id)

让我感到困惑的是......我什么时候应该检查所有状态?我的意思是,我会在一段时间内检查所有工作的状态吗?这会让服务器超时,任何想法我怎么能这样做?

3 个答案:

答案 0 :(得分:3)

我不会在这里粘贴任何代码,因为看起来你对如何写作业非常熟悉,但想想以下想法:

你应该有一个resque作业,它可以获取和处理的数组。 此resque作业为每个ID创建单个resque作业,以便并行处理它们。 在为特定ID创建resque作业之后,它将创建另一个resque作业,它获取id列表并定期检查它们以查看它们是否已完成。完成后,此作业将向用户发送电子邮件。

通过这种模式,你可以享受所有的世界:

  1. 每个ID都有自己的工作。
  2. 并行执行。
  3. 状态检查在后台完成,因此用户不会超时。
  4. 更新:

    支票转发作业的伪代码:

    class CheckerJob
      @queue = :long
    
      def self.perform(ids)
        finished = []
        while finished.size < ids.size
          ids.each do |id|
            finished << id if job_finished?(id)
          end
          sleep 10
        end
        send_email_to_user
      end
    end
    

    现在您要做的就是实施job_finished?(id)send_email_to_user方法。

答案 1 :(得分:0)

简单的解决方案是让你的工作列出一些ID:

Class Job
  def self.perform(ids)
    threads = ids.inject([]) do |memo, id|
      memo << Thread.new { # whatever }
    end
    ThreadsWait.join_all(*threads)
    # All threads are done
    # Notify user that job is finished
  end
end

没有工作来检查这个是否已经完成。如果您打算采用这种方式,请订阅Redis事件http://redis.io/topics/internals-rediseventlib

更新:添加了多线程

答案 2 :(得分:0)

这样做怎么样?

Resque.enqueue_to("page_processes#{user.id}", ProcessPage, page_id)

#code in ProcessPageWorker below
def self.perform(page_id, user_id)
  #work
  # code below notifies user if the 'page_processes' queue is equal to 1
  notify_user if Resque.size("page_processes#{user_id}") == 1
end

我们将作业排入名为“page_processes”的队列中,加上用户的ID。完成每项工作后,我们会检查“page_processes#{user_id}”队列的大小。如果队列等于1,则意味着正在处理的作业是队列中的最后一个作业,因此我们应该通知用户。我们在队列名称中包含user_id以确保队列的唯一名称。

如果有帮助,请告诉我。