I had the chance to use
whenever to schedule a task in Rails, and I'm writing this post for future reference. I know there are other ways to schedule regular tasks in Rails, but this is one - maybe the most - simple way to do it.
Note: Guide is for Linux or MacOS systems.
Cron is a job scheduler that lets you execute recurring tasks at fixed times (e.g. every minute, every hour, every day at 3pm).
Jobs are written in a file called the crontab (short for “cron table”), typically saved here:
Whenever is a gem that helps you set up cron jobs. Instead of having to manually edit the crontab yourself, you can let
whenever update the crontab for you by writing your jobs in Ruby code. You'll make your edits in
Note: One thing worth mentioning (this tripped me up at first) is that the actual task itself (in my case, sending out batch messages) should not be written in the crontab, or in
schedule.rb, the Rails file for writing in your crontab. The task itself should be written separately as a Rake task. You can then schedule that Rake task on a regular basis as a cron job.
Include it in your app's
Gemfile, and run
bundle to install.
gem 'whenever', require: false
config/schedule.rb is the file for specifying when to execute the job, and the name of the Rake task (again, the actual task should be written in a separate file).
Execute this from your Rails app root to create the
bundle exec wheneverize .
Now, write your job specifics in
schedule.rb. For example, if you want to execute the Rake task
batch:send_messages every minute:
every 1.minute do rake 'batch:send_messages' end
You can also do
every 2.hours and
every 1.day and so on.
Let whenever write the cron job into the crontab.
bundle exec whenever --update-crontab
After updating the crontab, open it to edit the Rails environment.
RAILS_ENV is set to production, but if you're using a development environment, change it to development. You can edit the crontab by writing the edit command into your terminal:
Crontab example (edited to have
RAILS_ENV be development):
# Begin Whenever generated tasks for: /Users/<USER>/<APPNAME>/config/schedule.rb at: 2019-01-14 18:15:41 +0900 * * * * * /bin/bash -l -c 'cd /Users/<USER>/<APPNAME> && RAILS_ENV=development bundle exec rake batch:send_messages --silent' # End Whenever generated tasks for: /Users/<USER>/<APPNAME>/config/schedule.rb at: 2019-01-14 18:15:41 +0900
bundle exec whenever --clear-crontab
Rake tasks follow a specific naming convention - namespace and task name. Namespaces are for grouping certain tasks together. For example, in the case below, if you had multiple batch tasks, you could put them all under
Generate a file for your Rake task under
lib/tasks/batch.rake. They follow the formula of:
rails g task <NAMESPACE> <TASKNAME>
So to generate our
send_messages task in the
batch namespace, we'll enter the following into terminal:
rails g task batch send_messages
Now write your task, which takes two parameters:
desc, which is an arbitrary description of your task, and
task, which is the code to be executed.
namespace :batch do desc 'Send out batch messages' task send_messages: :environment do # The code to actually send our messages would go here end end
You can test your Rake task by executing it from the command line as below.
Thanks for reading!
One of the most consolidated misconceptions about programming, since the early days, is the idea that such activity is purely technical, completely exact in nature, like Math and Physics. Computation is exact, but programming is not.