resque-status and resque-scheduler for delayed jobs

限于喜欢 提交于 2020-01-13 06:18:09

问题


I used resque-scheduler for delay jobs in previous code:

Resque.enqueue_in(options[:delay].seconds, self, context)

Now I want to include resque-status to do the job but have no idea how they can work together. The latest resque-status source code supports scheduler, as in the source code:

https://github.com/quirkey/resque-status/blob/master/lib/resque/plugins/status.rb

# Wrapper API to forward a Resque::Job creation API call into a Resque::Plugins::Status call.
# This is needed to be used with resque scheduler
# http://github.com/bvandenbos/resque-scheduler
def scheduled(queue, klass, *args)
  self.enqueue_to(queue, self, *args)
end

end

But I'm not sure how to use it. Shall I just call SampleJob.scheduled(queue, myclass, :delay => delay) instead of SampleJob.create(options)?

======================================================================

Also, there is Support for resque-status (and other custom jobs):

https://github.com/bvandenbos/resque-scheduler

Some Resque extensions like resque-status use custom job classes with a slightly different API signature. Resque-scheduler isn't trying to support all existing and future custom job classes, instead it supports a schedule flag so you can extend your custom class and make it support scheduled job.

Let's pretend we have a JobWithStatus class called FakeLeaderboard

class FakeLeaderboard < Resque::JobWithStatus
  def perform
    # do something and keep track of the status
  end
end

And then a schedule:

create_fake_leaderboards:
  cron: "30 6 * * 1"
  queue: scoring
  custom_job_class: FakeLeaderboard
  args:
  rails_env: demo
  description: "This job will auto-create leaderboards for our online demo and the status will update as the worker makes progress"

But it seems only for recurring jobs. I can find params of cron, but not delay. So how can I handle delayed jobs with it?

Thanks!


回答1:


I had the same issue and I solved by myself by implementing a module which provide a runner for "statused" jobs.

module Resque # :nodoc:

  # Module to include in your worker class to get resque-status
  # and resque-scheduler integration
  module ScheduledJobWithStatus

    extend ActiveSupport::Concern

    included do
      # Include status functionalities
      include Resque::Plugins::Status
    end

    # :nodoc:
    module ClassMethods

      # This method will use a custom worker class to enqueue jobs
      # with resque-scheduler plugin with status support
      def enqueue_at(timestamp, *args)
        class_name = self.to_s # store class name since plain class object are not "serializable"
        Resque.enqueue_at(timestamp, JobWithStatusRunner, class_name, *args)
      end

      # Identical to enqueue_at but takes number_of_seconds_from_now
      # instead of a timestamp.
      def enqueue_in(number_of_seconds_from_now, *args)
        enqueue_at(Time.now + number_of_seconds_from_now, *args)
      end

    end
  end

  # Wrapper worker for enqueuing
  class JobWithStatusRunner
    # default queue for scheduling jobs with status
    @queue = :delayed

    # Receive jobs from {Resque::ScheduledJobWithStatus} queue them in Resque
    # with support for status informations
    def self.perform(status_klass, *args)
      # Retrieve original worker class
      klass = status_klass.to_s.constantize
      # Check if supports status jobs
      unless klass.included_modules.include? Resque::Plugins::Status
        Rails.logger.warn("Class #{klass} doesn't support jobs with status")
        return false
      end
      Rails.logger.debug("Enqueing jobs #{klass} with arguments #{args}")
      klass.create(*args)
    rescue NameError
      Rails.logger.error("Unable to enqueue jobs for class #{status_klass} with args #{args}")
      false
    end
  end

end

In this way you can enqueue your jobs with this simple syntax:

# simple worker class
class SleepJob

  # This provides integrations with both resque-status and resque-scheduler
  include Resque::ScheduledJobWithStatus

  # Method triggered by resque
  def perform
    total = (options['length'] || 60).to_i
    1.upto(total) { |i| at(i, total, "At #{i} of #{total}"); sleep(1) }
  end

end

# run the job delayed
SleepJob.enqueue_in(5.minutes)
# or
SleepJob.enqueue_at(5.minutes.from_now)

Just drop the module in resque initializer or in lib folder. In the latter case remember to require it somewhere.




回答2:


resque-scheduler will call the scheduled method on the supplied class whenever it creates the job for your workers to consume. It also nicely passes both the queue name and class name as a string so you can create a class level method to handle scheduled job creation.

While Fabio's answer will solve the problem, it is a bit over-engineered to answer your specific question. Assuming you have a JobWithStatus class that all of your resque-status workers inherit from, you need only add the scheduled method to it for it to work with the resque-scheduler as so:

class JobWithStatus
  include Resque::Plugins::Status

  def self.scheduled(queue, klass, *args)
    Resque.constantize(klass).create(*args)
  end
end


来源:https://stackoverflow.com/questions/18139879/resque-status-and-resque-scheduler-for-delayed-jobs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!