Whenever: Cron Jobs in Ruby
Whenever is a Ruby gem that provides a clear syntax for writing and deploying cron jobs.
Prerequisites
- Ruby: A Ruby environment (version compatible with your project) is required.
- Bundler (recommended): For managing gem dependencies.
- Cron daemon: A running cron daemon on the target system to execute the scheduled tasks.
Installation
You can install Whenever as a gem or include it in your project's Gemfile.
As a Gem
$ gem install whenever
With Bundler (Gemfile)
Add the following line to your Gemfile:
gem 'whenever', require: false
Then, run bundle install to install the gem:
$ bundle install
Configuration
Whenever uses a config/schedule.rb file to define your cron jobs.
Initializing schedule.rb
Navigate to your project's root directory and run wheneverize:
$ cd /apps/my-great-project # Replace with your project path
$ bundle exec wheneverize .
This command creates an initial config/schedule.rb file. Ensure the config directory exists in your project.
Defining Cron Jobs
Edit config/schedule.rb to define your tasks.
Basic Scheduling
every 3.hours do
runner "MyModel.some_process"
rake "my:rake:task"
command "/usr/bin/my_great_command"
end
every 1.day, at: '4:30 am' do
runner "MyModel.task_to_run_at_four_thirty_in_the_morning"
end
every 1.day, at: ['4:30 am', '6:00 pm'] do
runner "Mymodel.task_to_run_in_two_times_every_day"
end
every :hour do # Shortcuts: :hour, :day, :month, :year, :reboot
runner "SomeModel.ladeeda"
end
every :sunday, at: '12pm' do # Days of the week, :weekend, :weekday
runner "Task.do_something_great"
end
every '0 0 27-31 * *' do # Raw cron syntax
command "echo 'you can use raw cron syntax too'"
end
Custom Job Types
Define your own job types using job_type:
job_type :awesome, '/usr/local/bin/awesome :task :fun_level'
every 2.hours do
awesome "party", fun_level: "extreme"
end
Whenever ships with command, runner, and rake job types. Their definitions are:
job_type :command, ":task :output"
job_type :rake, "cd :path && :environment_variable=:environment :bundle_command rake :task --silent :output"
job_type :script, "cd :path && :bundle_command script/:task :output"
job_type :runner, "cd :path && :bundle_command :runner_command -e :environment ':task' :output"
Default values for job types:
:path: Defaults to the directory wherewheneverwas executed.:environment_variable: Defaults to 'RAILS_ENV'.:environment: Defaults to 'production'.:output: Configures output redirection (see Whenever Wiki for details).
Environment Variables and Settings
- Job Template: By default, jobs run with
bash -l -c 'command...'. You can change this:set :job_template, "bash -l -c ':job'" # Or disable it: set :job_template, nil - Chronic Options: Customize how Whenever parses dates and times using
set :chronic_options:
Refer to the Chronic gem documentation for available options.set :chronic_options, hours24: true - Email Recipient (
MAILTO): Configure where job output is sent.- Global:
env 'MAILTO', 'output_of_cron@example.com' - Per interval block:
every 3.hours, mailto: 'my_super_command@example.com' do command "/usr/bin/my_super_command" end - Per job:
every 3.hours do command "/usr/bin/my_super_command", mailto: 'my_super_command_output@example.com' end
- Global:
Comments
Add descriptions to your cron entries:
every 1.hours, description: "My job description" do
command "/usr/bin/my_great_command"
end
Build & Run
Whenever does not "run" in the traditional sense; it generates cron syntax that is then installed into your system's crontab.
Previewing Cron Output
To see the cron syntax generated from your config/schedule.rb without modifying your crontab:
$ cd /apps/my-great-project # Replace with your project path
$ bundle exec whenever
This command will output the cron entries to your console.
## [message] Above is your schedule file converted to cron syntax; your crontab file was not updated.
## [message] Run `whenever --help' for more options.
Deployment
Deployment with Whenever involves writing the generated cron jobs to the system's crontab.
Updating the Crontab
To write the cron jobs defined in config/schedule.rb to your system's crontab:
$ whenever --update-crontab
Common Options for whenever --update-crontab
- Specify User: Install the crontab for a specific user. This is crucial for tasks requiring different user permissions.
Note: If$ whenever --update-crontab --user app--useris not specified, cron jobs are generated for the current user. - Specify Schedule File: Use a different schedule file.
$ whenever --update-crontab --load-file config/my_schedule.rb - Override Crontab Command: Use a custom command to interact with crontab (e.g., for
sudo).$ whenever --update-crontab --crontab-command 'sudo crontab'
Listing Installed Cron Jobs
You can verify the installed cron jobs using the standard crontab -l command:
$ crontab -l
Clearing Crontab Entries
To remove Whenever-managed cron entries from your crontab:
$ whenever --clear-crontab
Capistrano Integration
Whenever includes Capistrano recipes for automated deployment.
In your deploy.rb or Capistrano configuration:
# Add to your Capfile
# require 'whenever/capistrano'
# In deploy.rb
set :whenever_roles, :db # Default: :db
set :whenever_identifier, -> { fetch :application } # Default: application name
set :whenever_environment, -> { fetch :rails_env, fetch(:stage, "production") } # Default: production
set :whenever_variables, -> { "environment=#{fetch :whenever_environment}" }
set :whenever_path, -> { fetch :latest_release } # Default: latest release path
# To update crontab on deploy:
after "deploy:symlink:release", "whenever:update_crontab"
# To clear crontab on rollback:
after "deploy:rollback", "whenever:update_crontab"
The Capistrano tasks are:
whenever:update_crontab: Updates the crontab entries on the specified roles.whenever:clear_crontab: Clears Whenever-managed crontab entries.
Troubleshooting
- Cron jobs not running:
- Check crontab: Use
crontab -lto ensure the jobs are actually installed. - User permissions: Verify that the cron jobs are installed for the correct user (
whenever --update-crontab --user <username>). Tasks requiring specific user permissions will fail if run by the wrong user. - Environment: Cron's environment is often minimal. Ensure your
schedule.rbsets necessary environment variables or usesbash -l -c(Whenever's defaultjob_template) to load a full environment, especially for RVM/rbenv setups. - Paths: Ensure all commands (e.g.,
rake,runner, custom scripts) have their full paths or that yourPATHenvironment variable is correctly set within the cron environment. - Output: Check the logs or email configured in
MAILTOfor any error messages.
- Check crontab: Use
whenevercommand not found:- If using Bundler, ensure you prefix commands with
bundle exec(e.g.,bundle exec whenever --update-crontab). - Verify the gem is installed (
gem list whenever).
- If using Bundler, ensure you prefix commands with
config/schedule.rbnot found:- Ensure you are running
wheneverfrom your project's root directory. - Confirm the file exists at
config/schedule.rbor specify its path with--load-file.
- Ensure you are running
- Syntax errors in
schedule.rb:- Whenever will report Ruby syntax errors when you run
whenever. Correct these in yourschedule.rbfile.
- Whenever will report Ruby syntax errors when you run
- Time parsing issues:
- If
at:options are not behaving as expected, check yourset :chronic_optionsinschedule.rband refer to the Chronic gem documentation for parsing rules.
- If