In the project that I'm working currently, I was asked to look out for ways to replace the scheduling jobs through crontab in favour of some scheduler that can control/schedule run the tasks at regular interval as long as the application is up and running. Thanks to my comrade in Dev-Ops team (Ranjib Dey) who directing my attention to rufus-scheduler.
rufus-scheduler - Things can't be simpler! Let us see how simple it is in action with a sample code
First step to usage is install the gem; so, find below the command for the same. You run it from the root of your application folder and I assume that you use rvm (if not, prefix the command with - sudo )
> gem install rufus-scheduler
Now, when the rails application gets kick-started, it reads all .rb files under config/initializers directory as part of its initialization process. This step in rails start-up, is what we'll take advantage of. So, let us create a new file, say my_tasks_scheduler.rb, in config/initializers directory.
<my_rails_app>
| -- app
| -- config
| -- initializers
| -- my_tasks_scheduler.rb
| -- db
| -- ...
| -- ...
| -- lib
| -- tasks
| -- tempfile.rake
The contents of the file my_tasks_scheduler.rb would be like:
require 'rufus/scheduler' # Need this to make use of Rufus::Scheduler
require 'rubygems' # Need this to make use of any Gem, in our case it is rufus-scheduler
require 'rake' # Need this to make use of Rake::Task
# 'tempfile.rake' is the rake file I had defined under lib/tasks directory in my rails application
load File.join(RAILS_ROOT, 'lib', 'tasks', 'tempfile.rake')
# 'misc.rake' is the rake file defined under railties/lib/tasks directory of the installed rails version that your application makes use of.
# 'misc.rake' is not required to be loaded if none of your rake tasks that you invoke are dependent on :environment task, directly or indirectly
# If this file is not loaded, you would see an error message like "Don't know how to build task :environment"
load File.join('lib', 'tasks', 'misc.rake')
# OPTION 1: If you want to run the scheduler as part of your very own rails process then you may adopt this option
temp_files_cleaning_scheduler = Rufus::Scheduler.start_new
# Making use of the syntax used in Crontab
temp_files_cleaning_scheduler.cron '*/1 * * * *' do
task = Rake::Task["tempfile:delete_all"]
task.reenable # If only you do this, will your rake task run the next time you invoke it.
task.invoke
end
#OPTION 2: If for whatever reason (say, for performance reasons) you want to run your rake tasks as seperate process independent of your rails application, then you may adopt this option
temp_files_cleaning_scheduler = Rufus::Scheduler.start_new
#Making use of a more intutive approach, instead of Cron syntax
temp_files_cleaning_scheduler.every "1m" do
# Programmatically, kick-starting the rake task from the command line
system "rake tempfile:delete_all RAILS_ENV=#{RAILS.env}"
end
And that is it, you are all set for action...
Additional references that are worth reading are mentioned below:
- Rufus Scheduler home page
- Dead simple task scheduling in Rails
- Rake tutorial by Jason Seifer
- Custom Rake Tasks by Railscasts
- Jay Fields' thoughts on testing rake tasks
- John Barnette on Rake
- Questions in StackOverflow