update : The scheduler has moved. It has become the rufus-scheduler gem.
You can install it with :
sudo gem install rufus-scheduler
Backward compatibility has been preserved. This is still ok :
require 'rubygems'
require 'openwfe/util/scheduler'
scheduler = OpenWFE::Scheduler.new
scheduler.start
# ...
Though the new gem will simply require :
require 'rubygems'
require 'rufus/scheduler'
scheduler = Rufus::Scheduler.new
scheduler.start
# ...
This ‘move’ is part of a move of some of the OpenWFEru subprojects from OpenWFEru to Rufus
OpenWFEru being a workflow / business process engine needs a scheduler for tasks to execute later (at) and tasks to execute repetitively (cron).
This scheduler isn’t OpenWFE focused so this page details how to use it outside of the OpenWFEru context.
Like the rest of OpenWFEru, it’s licensed under the BSD license.
The OpenWFEru scheduler was presented in Ilya Grigorik’s blog post about Scheduling tasks in Ruby / Rails.
You don’t need the full OpenWFEru suite to use the scheduler. Only those 2 files are required :
lib/openwfe/util/otime.rb
lib/openwfe/util/scheduler.rb
They are all located in the util subdir of OpenWFEru.
The “openwferu-scheduler” is available in its own gem, just do
[sudo] gem install openwferu-scheduler
to get it. You can then use it straightaway like in
require 'rubygems'
require 'openwfe/util/scheduler'
include OpenWFE
scheduler = Scheduler.new
scheduler.start
scheduler.schedule_in("1h12m") do
puts "...taking out the garbage (as requested one hour and twelve minutes ago)"
end
# ...
The rdocumentation for the scheduler. It is the most up to date source of information about the scheduler.
“at” jobs are jobs to be executed in the future once (and only once). They are registered via the schedule_in() and the schedule_at() methods of the Scheduler.
The basic idea is :
scheduler.schedule_in("1h12m") do
puts "one hour and twelve minutes later..."
end
scheduler.schedule_at("Fri Jul 20 09:07:02 +0900 2007") do
puts "on this beautiful July day..."
end
require 'time'
#
# so that the Time class now features the parse() methods
scheduler.schedule_at Time.parse('18 July 2007 14:09:00') do
puts "yet another beautiful July day in the current time zone..."
end
Note that jobs meant to be scheduled at past dates will be triggered immediately but not scheduled. There is a :discard_past parameter to prevent the immediate triggering.
jobid = scheduler.schedule_at yesterday do
puts "yesterday or today ?"
end
#
# the message will be displayed immediately. 'jobid' will yield nil.
jobid = scheduler.schedule_at(yesterday, :discard_past => true) do
puts "yesterday or today ?"
end
#
# the message will not be displayed. 'jobid' will yield nil.
An example of “at” jobs (mostly schedule_in()).
Cron jobs have been around since as long as unixes have. The cron aspect of our ruby scheduler follows thus the established practice
scheduler.schedule("1-60/3 * * * mon-fri") do
puts "...popping up every 3 minutes on weekdays..."
end
You can type “man 5 crontab” on your favourite unix box or look there to learn more about the cron format.
Since OpenWFEru 0.9.16, cron jobs can be specified at the second level.
scheduler.schedule("7 1-60/3 * * * *") do
puts "...popping up every 3 minutes, at the seventh second ..."
end
The first column is dedicated to seconds and optional, it behaves like the other columns, accepting a single value, or list or ranges of values.
scheduler.schedule("7,27 * * * * *") do
puts "...popping up at the seventh and the twenty-seventh seconds..."
end
For something more relaxed than cron :
scheduler.schedule_every("12m45s") do
puts "...popping up every 12 minutes and 45 seconds..."
end
Since OpenWFEru 0.9.17, ‘every’ jobs can reschedule/unschedule themselves.
Two examples in an “internet electronic mail” context :
schedule.schedule_every "5h" do |job_id, at, params|
mails = $inbox.fetch_mails
mails.each { |m| $inbox.mark_as_spam(m) if is_spam(m) }
params[:every] = if mails.size > 100
"1h" # lots of spam, check every hour
else
"5h" # normal schedule, every 5 hours
end
end
schedule.schedule_every "10s" do |job_id, at, params|
#
# polls every 10 seconds until a mail arrives
$mail = $inbox.fetch_last_mail
params[:dont_reschedule] = true if $mail
end
The scheduling methods each return a job identifier that can be used to unschedule the jobs :
job_id = scheduler.schedule_every("12m45s") do
puts "...popping up every 12 minutes and 45 seconds..."
end
# a bit later...
scheduler.unschedule(job_id)
To stop the scheduler :
scheduler.stop
By default, the scheduler checks for jobs to trigger 4 times per second. This is configurable at instantiation.
scheduler = OpenWFE::Scheduler.new(:scheduler_precision => 0.500)
scheduler.start
#
# instatiates a scheduler that checks its jobs twice per second
# (the default is 4 times per second (0.250))
puts "scheduler precision is #{scheduler.precision}"
Since OpenWFEru 0.9.16, it’s possible to tag jobs at schedule time.
scheduler.schedule_in "2h", :tags => "backup" do
init_backup_sequence()
end
scheduler.schedule "0 24 * * *", :tags => [ "old_day", "backup" ] do
init_backup_sequence()
end
scheduler.schedule "0 09 * * *", :tags => "new_day" do
unlock_building_doors()
end
# fetching the jobs with the backup tag
backup_jobs = scheduler.find_jobs('backup')
# and cancelling them ...
backup_jobs.each { |j| scheduler.unschedule(j.job_id) }
If you have questions, feel free to ask them on OpenWFEru’s users mailing list.
In the context of OpenWFEru, the persistence responsibility is assumed by the engine, not the scheduler.
if you don’t need it :
$ sudo gem uninstall openwferu-scheduler
(to be continued)