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.
What are cron jobs?
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: /usr/bin/
Use whenever
for cron jobs in Rails
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 schedule.rb
Note: One thing worth mentioning is that the actual task itself (in my case, sending out batch messages periodically) 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.
Steps
1. Install whenever
Include it in your app's Gemfile
, and run bundle
to install.
gem 'whenever', require: false
2. Schedule your cron job in schedule.rb
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 schedule.rb
file:
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.
3. Write the whenever
task to your crontab
Let whenever
write your job into the crontab.
bundle exec whenever --update-crontab
Important
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 production
).
whenever --update-crontab --set environment='development'
For your reference, this is what your crontab will look like after running this command (RAILS_ENV
is 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
Other commands
- Display crontab:
crontab -l
- Wipe crontab of your
whenever task
:bundle exec whenever --clear-crontab
4. Create the Rake task
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 batch
.
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.
For example:
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.
rails batch:send_messages
Thanks for reading!
Top comments (9)
Easy to understand.
Thank you!
Thank you for your post
btw, you can run this command to update crontab for development environment without actually editing the crontab file
That's really convenient! I'll update the post accordingly. Thank you :)
Thanks for the comment, I'm happy to hear it!
I've made a new way of using "cron" in Rails, because I find the other ways cumbersome and error prone. Check out arask.
Hi, new to rails here, running rails g task keeps over writing my rake file, do you have any idea why that could be? any help would be appreciated greatly!
Hi, why are you running
rails g task
multiple times? You only need to create the task once. Running the task is done via a command likerails batch:send_messages
(Example taken from my blog post, please use your actual task name and namespace).Hi Risa, Is there any alternative for scheduling jobs in seconds because chron jobs scheduling requires time to be in minutes
Hi Deepak, I feel like that question goes beyond the scope of this post since it's a limitation of cron itself, not the
whenever
gem π€ How about looking into solutions like the ones suggested here?How to run scripts every 5 seconds?
Some comments have been hidden by the post's author - find out more