Scheduling tasks is something we all need to know to do, for it’s quite common in applications. Fetching feeds, indexing some data, processing files at a periodical time, that happens a lot. You are probably quite familiar then with the linux cron, if you had to deal with scheduling stuff in the past, but there is something you may not. Let me introduce you the Whenever gem. What is it? A simple gem to schedule tasks writing them in nice ruby syntax…just let the gem work it’s magic and deal with the cron.
In order to install it, you have to add first the github source, only if you never done it :$ gem sources -a http://gems.github.com
$ sudo gem install javan-whenever
To get started, just place yourself in the app path and type
$ wheneverize .
This will create an initial config/schedule.rb for you.
There you can nicely write tasks to run.
Some examples are:every 3.hours do
runner "MyModel.some_process"
rake "my:rake:task"
command "/usr/bin/my_great_command"
end
every 1.day, :at => '4:30 am' do
runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
end
every :hour do # Many shortcuts available: :hour, :day, :month, :year, :reboot
runner "SomeModel.ladeeda"
end
every :sunday, :at => '12pm' do # Use any day of the week or :weekend, :weekday
runner "Task.do_something_great"
end
Another nice thing to do is integrate it with Capistrano.
after "deploy:symlink", "deploy:update_crontab"
namespace :deploy do
desc "Update the crontab file"
task :update_crontab, :roles => :db do
run "cd #{release_path} && whenever --update-crontab #{application}"
end
end
The official documentation provides this way to integrate it, but we found some little details, and the solution is here for you.
If you integrate it by the regular way, when making multiple deploys, it will configure several tasks to run in your cron file. Why? Because the path of the current application changed, and the gem uses the path (by adding a comment line) when updating the cron. What should we do then? Simple, change the run line with this:run "cd #{current_path}; whenever -i #{current_path}/config/schedule.rb"
What have we done? We used the -i option, which makes an update, but passing the comment we want, and make it not to change in every deploy.
Feel free to try it and leave your comments !!



Ryan Bates from Railscasts uses this line:
run “cd #{release_path} && whenever—update-crontab #{application}”
What is the difference between the two?
@Robby
The difference between running multiple commands separated by ; and && is that the command following && will only run if the first command completed successfully, while the command following a ; will run regardless of the status of the first command.
Hi,
Make sure you include the environment as well, otherwise when you deploy your app on a staging server the wheneverized crontab will be scoped to production.
run “cd #{current_path} && whenever—update-crontab #{application} -s environment=#{rails_env}”
Josh
If you use ”#{current_path}/config/schedule.rb” as your identifier, it will change with each deploy because current_path is the path to the newest release. This will cause duplicate cron jobs!
You need to use a non changing string for your identifier to prevent this. That’s why my example uses ”#{application}”, but any string will work.
Also, there’s no point in running the the whenever command if the cd command fails which is why I prefer to use &&.
We found out that even when using the ‘update-crontab’ option with ”#{application}” it does not override the existing cron job, but writes a new one. This is because we use capistrano, and it creates symbolic links for the new deploys, and the gem considers it as a new application. That’s why we pass the identifier we want, and just override the old one.