Search code examples
rubyrufus-scheduler

Rufus Scheduler: Every day, start a job at time X and process in batches with a fixed interval


I am trying to figure out how to be able to do the following.

I want to start a job at 12:00pm every day which computes a list of things and then processes these things in batches of size 'b'. and guarantee an interval of x minutes between the end of one batch and the beginning of another.

schedule.cron '00 12 * * *' do
    # things = Compute the list of things
    schedule.interval '10m', # Job.new(things[index, 10]) ???
end

I tried something like the following but I hate that I have to pass in the scheduler to the job or access the singleton scheduler.

class Job < Struct.new(:things, :batch_index, :scheduler)
  def call
    if (batch_index+1) >= things.length
      ap "Done with all batches"
    else
      # Process batch
      scheduler.in('10m', Dummy.new(things, batch_index+1, scheduler))
    end
  end
end

scheduler = Rufus::Scheduler.new
schedule.cron '00 12 * * *' , Dummy.new([ [1,2,3] , [4,5,6,7], [8,9,10]], 0, scheduler)

Solution

  • with a bit of help from https://github.com/jmettraux/rufus-scheduler#scheduling-handler-instances

    I'd prepare a class like:

    class Job
    
      def initialize(batch_size)
    
        @batch_size = batch_size
      end
    
      def call(job, time)
    
        # > I want to start a job (...) which computes a list of things and
        # > then processes these things in batches of size 'b'.
    
        things = compute_list_of_things()
    
        loop do
    
          ts = things.shift(@batch_size)
    
          do_something_with_the_batch(ts)
    
          break if things.empty?
    
          # > and guarantee an interval of x minutes between the end of one batch
          # > and the beginning of another.
    
          sleep 10 * 60
        end
      end
    end
    

    I'd pass an instance of that class to the scheduler instead of a block:

    scheduler = Rufus::Scheduler.new
    
    # > I want to start a job at 12:00pm every day which computes...
    scheduler.cron '00 12 * * *', Job.new(10) # batch size of 10...
    

    I don't bother using the scheduler for the 10 minutes wait.