Search code examples
ruby-on-railsrufus-scheduler

Rufus Scheduler vs Loop with Sleep


I need to run an ActiveJob in my Rails 5 application as often as possible.

Up until now, I was using a cron job that was defined using the whenever gem (used Crono in the past).

This approach boots up the entire rails app before it does its thing, and then shuts down and does it all over again. I wish to avoid it, and instead have a persistent "service" that does the job.

I bumped into the Rufus Scheduler gem which seems nice, but then I started wondering if I need it at all.

So, my question is:

Are there any meaningful differences between these two options below:

# With Rufus
scheduler = Rufus::Scheduler.new
scheduler.every('1s') { puts 'hello' }
scheduler.join

# Without Rufus
loop { puts "hello" ; sleep 1 }

Note that either of these scripts will be executed with rails runner my_scheduler.rb as a docker container, and any solution must ensure the job runs once only (never two in parallel).


Solution

  • There are differences.

    Rufus-scheduler every will try to run every 1s, so at t0 + 1, t0 + 2, t0 + 3, etc. While the "sleep" variant will run at t0, t0 + wt1 + 1, t0 + wt1 + 1 + wt2 + 1, ... (where wtN = work time for Nth call of puts hello).

    Rufus-scheduler every will use rufus-scheduler work threads so that if there is an overlap (wt(Nb) > wt(Na)), Nb will occur anyway. This behaviour can be changed (see job options).

    Rufus-scheduler interval is closer to your sleep option:

    scheduler.interval('1s') { puts 'hello' }
    

    It places 1 second (or whatever time interval you want) between each run of puts 'hello'.

    For a simple do-sleep-loop, I'd go with the sleep option. But if you need more, rufus-scheduler has cron, interval, every and tuning options for them. And you can schedule multiple jobs.

    scheduler.cron('0 1 1 * *') do
      # every first of the month at 1am
      flush_archive
    end
    scheduler.cron('0 8,13,19 * * mon-fri') do
      # every weekday at 8am, 1pm, 7pm
      clean_dishes
    end
    scheduler.interval('1s') do
      puts 'hello'
    end