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.
whenever write your job into the crontab.
bundle exec whenever --update-crontab
Whenever takes into consideration your Rails app environment when writing to the crontab. If you're using the
development environment, then run the command with the option below (default is
whenever --update-crontab --set environment='development'
For your reference, this is what your crontab will look like after running this command (
# 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
- Display crontab:
- Wipe crontab of your
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!