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
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
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.
Есть Казань мужчины, которые в женщинах не нуждаются. Нет-нет г казань , у них все в порядке с сайт казани потенцией. Непорядок у них исключительно в голове. Подозреваю, что казань ооо женщина для них - нечто среднее между компании казани инопланетянином, с которым казань интернет трудно найти общий язык, и чесоткой, которая время от казань 2008 времени отвлекает от важных дел, и избавиться от школы казани нее нет никакой возможности. Я таких мужчин из телефоны казани вежливости, мягко, называю самодостаточными. вузы казани А женщины им не нужны потому, что у них и так все есть: работа, разнообразные адрес казань увлечения, места, в которых они проводят досуг. база казань Женщина для них - досадная помеха, которая может г казань ооо заставить перекроить устоявшийся агенства казань порядок вещей. За который они цепляются так зао казань судорожно, как турист, по ошибке забредший на нудистский справочник казани пляж, - за свои плавки.
Joseph Pearson is a Software Inventor who graduated — somewhat improbably — with honours in History. That might seem like a bumptious little detail to record, but seriously, what else am I going to do with it?
Just found your site, and I must say your light switch is damn geeky cool ;) Good luck