Switch_off Switch_on Switch_off
Inventive Labs: Web Problem Solvers

Scheduling periodic tasks in a Rails application [08112007]

There's a number of solutions around for forking out of the Rails http request cycle and performing intermittent or long-running operations within your Rails application environment. Some of the most well-documented options are summarised on the Rails wiki.

Looking for a way to schedule actions like 'fetch this feed every 15 minutes', 'clear out old sessions from the db', and 'take a snapshot of each site' for Blueprint, I investigated most of these options.

In the past I've used the reliable cron/runner combination, but this requires additional setup -- outside of your app -- on each server where the app is deployed. There are recipes out there for updating the cron table via Capistrano, but this is difficult to do in a way that preserves existing cron configuration. BackgrounDrb and AP4R both look accomplished, but are really intended to solve other (and bigger) problems.

OpenWFEru is a Workflow Engine, which sounds impressively enterprisey. I don't know much about that, but it comes with a pretty good scheduler — check out the API for it here.

This can be used to create a cron-like scheduler within Rails. I wanted the scheduler to run as a separate process alongside the pack of Mongrels that handle web requests, started and stopped by Capistrano. Ruby has a great 'daemons' gem that takes care of daemonising processes for you.

If you need something like this, install these two gems:

$ sudo gem install -y openwferu daemons

Then create script/schedule:

#!/usr/bin/env ruby
require 'rubygems'
require 'daemons'
APP_DIR = File.join(File.dirname(File.expand_path(__FILE__)), '..')

Daemons.run_proc(
  'schedule',
  :dir_mode => :normal, 
  :dir => File.join(APP_DIR, 'log'),
  :multiple => false,
  :backtrace => true,
  :monitor => true,
  :log_output => true
) do

  # Daemonising changes the pwd to /, so we need to switch 
  # back to RAILS_ROOT.
  Dir.chdir(APP_DIR)

  # Load our Rails environment.
  require File.join('config', 'environment')

  begin
    # Initialise the OpenWFE scheduler object.
    require 'openwfe/util/scheduler'
    scheduler = OpenWFE::Scheduler.new
    scheduler.start

    # Now assign jobs to the scheduler (see API). For example:
    scheduler.schedule_every('15m') { Feed.fetch_and_consume! }

    # Tell the scheduler to perform these jobs until the 
    # process is stopped.
    scheduler.join
  rescue => e
    RAILS_DEFAULT_LOGGER.warn "Exception in schedule: #{e.inspect}"
    exit
  end
end

Chmod this file to be executable, then test it:

$ chmod a+x script/schedule
$ script/schedule start

Monitor the file at log/schedule.output -- most errors will be reported here. It will log to log/<environment>.log. Run 'script/schedule' with no arguments to see how to stop and restart it, and do other daemonoid things if you like.

You can then create a task within your Capistrano deployment recipies along the lines of:

task :after_restart do
  run "RAILS_ENV=#{rails_env} #{current_path}/script/schedule stop"
  run "RAILS_ENV=#{rails_env} #{current_path}/script/schedule start"
end

Yet another web developer [Fri 16 Nov 2007, 8:23AM] said:

Just found your site, and I must say your light switch is damn geeky cool ;) Good luck

Walt [Sun 15 Jun 2008, 11:35AM] said:

Hi Joseph,

I am having problems using controllers in my backgrounDRB workers - to producing invoices for instance.

Will schedule "know" the entire Rails environment and gems (ApplicationController) - and thus allow me to instantiate an object of ApplicationController in one of my models (and the model being called in the schedule context)?

like:

class Invoice

  viewer = Class.new(ApplicationController)

..... end

cheers, walt

Joseph [Mon 16 Jun 2008, 1:06AM] said:

Well, yes, the scheduler will load the full Rails environment (see the 'require' line in the script) -- but instantiating controllers is not exactly a great idea, if you can avoid it. This is because so much of their initialisation assumes the existence of a real CGI request, which obviously you don't get from a script like this.

A better idea would be to refactor your controllers so that the functionality you're trying to access is in a model instead.

Walt [Thu 18 Sep 2008, 11:56AM] said:

Hi Joseph,

i'm back with another question in the same line of reasoning :)

From your answer to my latest question I was lead to believe that I could schedule a job which would "know" the models - and yet when I schedule a job, it does get scheduled but it knows nothing of my CronTable class? I have pastied the schedule.log here: http://www.pastie.org/274676

thank you for your time and interest!

cheers walt

Walt [Thu 18 Sep 2008, 12:12PM] said:

Hi Joseph,

ehhh - delay my last :)

I double checked (obviously I should have done that prior to start whining here) and lo'n behold: a simple lowercap "t" on my CronTable .(

My apologies, and thank you for sharing this great way of scheduling!

Cheers, Walt

Zeeshi [Fri 14 May 2010, 11:02PM] said:

Thanks for writing this….

It really helped me, specially when no good tutorial for beginners, which tells you the story from a to z, is available on openwferu_scheduler.

Cheers!

ValidaZenski [Fri 23 Jul 2010, 1:34PM] said:

Hello

Need escort girl in Belgium knows restrictions. Each Year vozrostaet number Services escort girl bruxelles increases, but, actually, must note, that the girls full of new here always had, even in old times. This is not surprising, because only escort girls brussels capable invite a full range of sex personals, not requiring color, Champagne and sweets, while their value is clearly not off-scale. call girl have long been Permanent, but unwilling guests of various Transmission the night life in Brussels, as well as the heroines of publications. And this, in fact, makes them more advertising,since services intimate acquaintance of the already very Famous in Belgium. Nevertheless, frequent customers are served by a girl One permanent address. After escort massage, afforded them pleasure, accustomed, and they know that each customer likes and dislikes – no. For example, not so difficult to find Belgium true fans love sex, escort antwerpen and other phenomena that have some time ago, is immoral. Now massage brussels quite naturally, and each Client always a its proposal.escortes bruxelles

Sincerely your friend Vlad

Only the comment field is required. Omitting the ID fields increases your risk of being mistaken for spam.

Preview or