Learn more  » Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Bower components Debian packages RPM packages NuGet packages

vistahigherlearning / logstash   deb

Repository URL to install this package:

Version: 1.4.2-1-2c0f5a1 

/ opt / logstash / vendor / bundle / jruby / 2.1 / gems / rufus-scheduler-2.0.24

  ..
  lib
  spec
  test
  CHANGELOG.txt
  CREDITS.txt
  LICENSE.txt
  README.rdoc
  Rakefile
  TODO.txt
  rufus-scheduler.gemspec
 

rufus-scheduler

rufus-scheduler is a Ruby gem for scheduling pieces of code (jobs). It understands running a job AT a certain time, IN a certain time, EVERY x time or simply via a CRON statement.

rufus-scheduler is no replacement for cron/at since it runs inside of Ruby.

alternatives / complements

A list of related Ruby projects :

More like complements :

installation

gem install rufus-scheduler

usage

The usage is similar to the one of the old rufus-scheduler. There are a few differences though.

require 'rubygems'
require 'rufus/scheduler'

scheduler = Rufus::Scheduler.start_new

scheduler.in '20m' do
  puts "order ristretto"
end

scheduler.at 'Thu Mar 26 07:31:43 +0900 2009' do
  puts 'order pizza'
end

scheduler.cron '0 22 * * 1-5' do
  # every day of the week at 22:00 (10pm)
  puts 'activate security system'
end

scheduler.every '5m' do
  puts 'check blood pressure'
end

This code summons a plain version of the scheduler, this can be made more explicit via :

scheduler = Rufus::Scheduler::PlainScheduler.start_new

This PlainScheduler accepts a :thread_name option :

scheduler = Rufus::Scheduler::PlainScheduler.start_new(:thread_name => 'my scheduler')

which might be helpful when tracking threads.

Note that if there is an EventMachine present and running,

scheduler = Rufus::Scheduler.start_new

will return an instance of Rufus::Scheduler::EmScheduler (leveraging EventMachine).

a note about cron jobs

This is a classical cron :

scheduler.cron '0 22 * * 1-5' do
  # every day of the week at 22:00 (10pm)
end

Rufus-scheduler supports three variants to that notation : seconds, last day of month and timezones.

scheduler.cron '13 0 22 * * 1-5' do
  # every day of the week at 22:00:13
end

scheduler.cron '0 22 L * *' do
  # every month on the last day at 22:00
end

scheduler.cron '0 22 * * 1-5 Europe/Paris' do
  # every day of the week when it's 22:00 in Paris
end
scheduler.cron '0 22 * * 1-5 Etc/GMT+2' do
  # every day of the week when it's 22:00 in GMT+2
end

The timezones are the ones supported by the ‘tzinfo’ rubygem (tzinfo.rubyforge.org/).

The timezone support was contributed by Tanzeeb Khalili.

“monthdays” are supported

scheduler.cron '0 22 * * sun#1,sun#2' do
  # every first and second sunday of the month, at 22:00
end

It’s also OK (since 2.0.19) to use L (for last monthday) or negative numbers.

scheduler.cron '0 22 * * sun#-1' do
  # every last sunday of the month, at 22:00
end

scheduler.join

Note that if you have a tiny script like this one :

require 'rubygems'; require 'rufus-scheduler'

scheduler = Rufus::Scheduler.start_new

scheduler.at 'Thu Mar 26 07:31:43 +0900 2009' do
  puts 'order pizza'
end

And you run it, it will exit immediately.

If you place

scheduler.join

at the end, it will make the current (main) thread join the scheduler and prevent the Ruby runtime from exiting.

You shouldn’t be exposed to this issue when using EventMachine, since while running EM, your runtime won’t exit.

important note about #join

DO NOT CALL this #join method if you’re running rufus-scheduler from Rails or Sinatra or any application that’s already some kind of ‘daemon’. It’s not necessary! #join is meant for small standalone scripts.

schedule.stop

scheduler.stop

This call stops the scheduler. It doesn’t unschedule jobs. If there are running jobs, they’re left running.

If you need to stop the scheduler and wait for all the jobs currently running to finish (without killing them), rufus-scheduler 2.0.20 brings a new :terminate => true option.

scheduler.stop(:terminate => true)
  # returns once all the jobs have been unscheduled and no jobs is running

block parameters

Scheduled blocks accept 0 or 1 parameter (this unique parameter is the job instance itself).

scheduler.every '5m' do
  puts 'check blood pressure'
end
scheduler.every '1y' do |job|
  puts "check cholesterol levels (#{job.job_id})"
end

See the class Job for more details :

rufus.rubyforge.org/rufus-scheduler/classes/Rufus/Scheduler/Job.html

the time strings understood by rufus-scheduler

require 'rubygems'
require 'rufus/scheduler'

p Rufus.parse_time_string '500'      # => 0.5
p Rufus.parse_time_string '1000'     # => 1.0
p Rufus.parse_time_string '1h'       # => 3600.0
p Rufus.parse_time_string '1h10s'    # => 3610.0
p Rufus.parse_time_string '1w2d'     # => 777600.0

p Rufus.to_time_string 60              # => "1m"
p Rufus.to_time_string 3661            # => "1h1m1s"
p Rufus.to_time_string 7 * 24 * 3600   # => "1w"

:blocking => true

Jobs will, by default, trigger in their own thread. This is usually desirable since one expects the scheduler to continue scheduling even if a job is currently running.

Jobs scheduled with the :blocking parameter will run in the thread of the scheduler, blocking it.

scheduler.in '20m', :blocking => true do
  puts "order ristretto"
  sleep 2 * 60
end
scheduler.in '21m' do
  puts "order espresso"
end

Hence, our espresso will come in 22 minutes instead of 21.

Warning, ‘cron’ behaves a bit differently than ‘in’ and ‘at’, if the scheduler is blocked working on a task, it may skip crons (while ins and ats get scheduled after).

scheduler.cron '0 16 * * * *' do
  puts "four o'clock tea"
end

If at 4pm the scheduler is in a blocking task, there will be no four o’clock tea.

:mutex => ‘that_mutex’

:blocking is nice but it is blocking the whole scheduler. What about something more fine-grained ? And also something that can be used with in, at, every and cron ?

scheduler.in '20m', :mutex => 'that_mutex' do
  puts "order ristretto"
  sleep 2 * 60
  puts "ah, that was delicious"
end
scheduler.in '21m' :mutex => 'that_mutex' do
  puts "order espresso"
end

the “order espresso” will only get triggered once the ristretto has been consumed. Rufus-scheduler will create a ‘that_mutex’ mutex and keep track of it. Don’t go on passing too many different mutex names, rufus-scheduler will keep track of each of them (they won’t get garbage collected).

It’s OK to use a mutex directly:

m = Mutex.new
# ...
scheduler.cron  '0 18 * * *', :mutex => m do
  # ...
end
scheduler.in '21m' :mutex => m do
  # ...
end

It can be handy for even more fine-grained control:

m = Mutex.new
# ...
scheduler.cron  '0 18 * * *', :mutex => m do
  # ...
end
scheduler.in '21m' do
  # non-critical
  m.synchronize do
    # critical
  end
  # non-critical
end

Please note that a mutex can also be used to prevent overlapping executions of the same job:

scheduler.every '5m', :mutex => 'the_mutex' do
  puts "order ristretto"
  # do something that might take more that 5 minutes...
  puts "ah, that was delicious"
end

But beware the cascades…

:mutex => [‘mutex_a’, ‘mutex_b’, …]

Multiple mutexes can be used to ensure exlusivity:

scheduler.in '20m', :mutex => 'mutex_r' do
  puts "order ristretto"
  sleep 2 * 60
end

scheduler.in '20m' :mutex => 'mutex_e' do
  puts "order espresso"
  sleep 3 * 60
end

scheduler.in '1h' :mutex => ['mutex_r', 'mutex_e'] do
  puts "code for fun"
end

This allow you order ristretto and espresso at same time, but when you coding it ensure you can’t order any thing, and when you ordering anything it ensure you can’t code.

Sure you can also use array of Mutex object directly:

mutex_r = Mutex.new
mutex_e = Mutex.new
# ...
scheduler.in '1h' :mutex => [mutex_r, mutex_e] do
  puts "code for fun"
end

:allow_overlapping => false

By default, every and cron jobs will “overlap”:

scheduler.every '3s' do
  4.times do |i|
    puts "hello #{i}"
    sleep 1
  end
end

You might end up with something that looks like

hello 0
hello 1
hello 2
hello 3
hello 3
hello 4
...

This every job will have overlaps. To prevent that:

scheduler.every '3s', :allow_overlapping => false do
  # ...
end

‘every’ jobs and :first_at / :first_in

This job will execute every 3 days, but first time will be in 5 days from now :

scheduler.every '3d', :first_in => '5d' do
  # do something
end

This job will execute every 3 days, starting from Christmas Eve at noon :

scheduler.every '3d', :first_at => '2009/12/24 12:00' do
  # do something
end

The chronic gem may help (chronic.rubyforge.org/) :

require 'chronic' # sudo gem install chronic

scheduler.every '3h', :first_at => Chronic.parse('this tuesday 5:00') do
  # do something starting this tuesday
end

Note : setting a :first_at/:first_in in the past will get rufus-scheduler to trigger for all the past schedules until now. Adding :discard_past => true will prevent this.

Loading ...