What is Cron?
Cron is a job scheduling system available in Linux & MacOS operating systems.
It can be used to run any program at any given time.
This includes Ruby code!
If there is a specific recurring task that you would like to run automatically every day, every week or even every hour, then Cron may be what you’re looking for.
Example of tasks include:
- Running a weekly database backup
- Generating a daily report of website activity
- Sending reminder emails
Let’s discover how you can make cron work for you!
Basics Of Cron
Every user can have a cron file where you define the tasks you want to run.
You can edit this file with the crontab -e
command.
Or list scheduled tasks with crontab -l
.
Example cron job:
0 0 * * * /opt/rubies/ruby-2.5.1/bin/rake db:backup
The syntax can be a bit tricky & you may not want to edit these files by hand all the time.
Are there any gems to make things easier for us?
Yes!
How to Use The Whenever Gem
Because cron syntax can be hard to remember we can use a gem like whenever
.
This gem helps you define cron jobs in Ruby.
Install the gem first.
Then, create the configuration file:
wheneverize . # [add] config/schedule.rb
Open it up.
You’ll see some commented-out examples, delete them if you want.
Let’s say we want a backup job that runs every hour.
Write this inside the “config/schedule.rb” file:
every 1.hour do rake "db:backup" end
Options include:
- rake (start a rake task defined on your current project, note that
db:backup
isn’t defined by default, but you can trydb:version
) - runner (Ruby class + method, like
Archive.backup_now
) - command (system command)
Now:
Run the whenever --update-crontab
command to generate the cron entries.
You should be able to see your new entry with crontab -l
.
This is what I got:
0 * * * * /bin/bash -l -c 'cd /home/jesus/testing && RAILS_ENV=production bundle exec rake db:backup --silent'
Notice that the task will run in production
mode.
Want to change that?
You can use this setting:
set :environment, "development"
This goes in your schedule.rb
file, at the top.
You can also use this command:
whenever --update-crontab --set environment=development
This creates all the tasks with “development” as the environment when you run this command.
More Whenever Examples
This example shows how you can be more specific.
Weekly task:
every :monday, at: "6:00 PM" do runner "Mail.send_weekly_newsletter" end
This example shows how to run the same task multiple times during the day.
Run task twice a day:
every :day, at: ["12:00 AM", "12:00 PM"] do command "rm tmp/testing.txt" end
Whenever Gem Logging & Troubleshooting
Once you have tasks in your crontab file (check with crontab -l
) you’re ready to go.
Next:
How do you know if the scheduled tasks are working correctly?
You can set up logging & read the output.
Enable logging by adding this at the top of your schedule.rb
file.
Configuration:
set :output, "log/cron.log"
Remember to run the whenever --update-crontab
command every time you make changes!
Log file still empty?
You’ll have to wait the scheduled time to see something happen.
Btw, if you see this error in the logs:
/bin/bash: bundle: command not found
That means cron isn’t running the same version of Ruby that you’re.
If you’re using a Ruby version manager:
Make sure to load it from the .bash_profile
file, instead of .bashrc
, so your cron tasks can use it.
Alternatives to Whenever
Whenever is a well-maintained gem & it works great.
But what are the alternatives?
Here’s a list:
- Heroku Scheduler, it’s a free job scheduling add-on for Heroku users. Not as flexible as cron itself but it gets things done
- Rufus Scheduler, a Ruby gem that replaces cron with an in-memory scheduler
- Sidecloq & Sidekiq-cron, both are Sidekiq add-ons that add recurring tasks to Sidekiq
Note that both Sidekiq addons want actual cron syntax for scheduling, so it won’t be as nice as whenever syntax.
The good thing is that they integrate with Sidekiq web UI.
Summary
You’ve learned how to schedule cron jobs using the whenever gem in Ruby!
Please share this article so more people can benefit from it.
Thanks for reading.
Might I suggest another alternative: delayed_job. It’s a direct extraction from Shopify where the job table is responsible for a multitude of core tasks.
Thanks for your suggestion, Rick!
I didn’t know about this gem, but it looks like it’s more aimed at being a background queue type of thing, more than running scheduled jobs that repeat.