/
Application Framework

Rails Cron Jobs with Whenever

Rails has no built-in scheduler — the de facto standard is the whenever gem, which lets you define jobs in a readable Ruby DSL (config/schedule.rb) and generates an actual crontab from it, rather than requiring you to hand-write cron syntax directly.

Syntax Notes

Whenever's DSL uses human-readable frequency methods (every 1.day, at: '2:30 am', every :sunday) rather than raw cron fields — it compiles schedule.rb down to a real crontab behind the scenes, viewable by running `whenever` with no arguments before writing it.

Examples

config/schedule.rb: daily cleanup at 2:30 AM
every 1.day, at: '2:30 am' do
  runner "MyModel.cleanup"
end
Run a rake task every 15 minutes
every 15.minutes do
  rake "my_task:run"
end
Write the compiled schedule to the real crontab
whenever --update-crontab

Gotchas

  • Editing config/schedule.rb does nothing to the actual crontab by itself — you must run `whenever --update-crontab` (typically as a deploy step, e.g. via Capistrano's whenever integration) to write the compiled schedule into cron.
  • Whenever's generated crontab jobs run outside your application's Bundler/RVM/rbenv context by default — the gem's environment-setting options (set :output, set :environment, and the job_type templates) exist specifically to work around cron's minimal shell environment, and skipping them is the most common cause of 'works locally, silently fails via cron' bugs.
  • Deploying without re-running `whenever --update-crontab` leaves the old schedule active — schedule.rb changes have zero effect on a running server until the crontab is regenerated and rewritten.

Best Practices

  • Wire `whenever --update-crontab` into your deploy pipeline automatically (Capistrano has an official whenever plugin) rather than remembering to run it by hand after every schedule.rb change.
  • Always redirect output in schedule.rb jobs (whenever's set :output config, or add >> log/cron.log 2>&1 to a custom job_type) so failures are visible instead of silently swallowed by cron's minimal environment.
  • Run `whenever` with no arguments locally to preview the exact crontab that will be generated before pushing it to a server — it's the fastest way to catch a DSL mistake before it reaches production.

Frequently Asked Questions

Do I need to know cron syntax to use the whenever gem?
Not really — whenever's DSL (every 1.day, at: '2:30 am', every :monday) is designed to be readable without cron knowledge, and it compiles down to a real crontab for you. Understanding cron helps when debugging the generated output, though.
Why isn't my updated schedule.rb taking effect on the server?
Editing schedule.rb only changes a Ruby file — it has no effect on the actual system crontab until you run `whenever --update-crontab`, which regenerates and rewrites the real cron entries. This step is often missing from manual, non-Capistrano deploy processes.
Why does my whenever-scheduled job fail via cron but work when I run it manually?
Cron jobs run outside your shell's Bundler/rbenv/RVM context by default. Make sure whenever's environment-setting options are configured (set :environment, and the appropriate job_type) so the generated crontab entries load the correct Ruby version and gemset.