Using the Whenever gem to manage scheduled cron jobs without installing it on the server
I've been using Javan's Whenever gem to manage scheduled jobs in my project and its fantastic!! There are many existing resources where you can learn more (readme, railscast google group) but I'd like to describe the specific way I'm using it
- When the gem is not installed on my server
- How administrators can use Capistrano to both schedule and unschedule your jobs
- How to use a library such as the Oracle client that requires certain environment variables
At the end of the day we want to have 2 capistrano tasks we can run to have cron call a rake task of ours on the schedule we want.
cap schedule_jobs cap unschedule_jobs
If we want to get fancy and pass a custom configuration argument that will be passed into the rake task.
cap schedule_jobs SOME_CONFIGURATION=false
When the gem is not installed on my server
Let's start with the Capfile
How does this differ from the example on the whenever site? Since the gem is not installed on the server we cannot call whenever from the command line so invoke the whenever:update_crontab rake task instead and to allow administrators to easily disable the scheduled jobs we define the unschedule_jobs capistrano task. Let's take a look at the whenever:update_crontab Rake task that gets this all done.
The actual whenever:update_crontab task just does the same the command line does but unless you add config.gem 'whenever' to your environment (which I don't since whenever is not needed by my app at runtime) we also have the other task that loads whenever and chronic from the vendor/gems directory.
At this point we've gotten Capistrano calling a rake task to invoke whenever even though the gem is localized in my application but not installed on the server.
How administrators can use capistrano to both schedule and unschedule your jobs
The whenever gem does not have any support for unscheduling but it will schedule whatever is included in your schedule.rb file so if that file tells it to schedule nothing that's the same as unscheduling. Its easy to do that by wrapping the entire file with unless ENV['UNSCHEDULE'] (remember the UNSCHEDULE parameter we passed in the Capfile?)
What's going on with the weird CronRakeTask? This brings us to the final point
How to use a library such as the Oracle client that requires certain environment variables
Cron loads its environment settings differently than an interactive shell and typically does not have all the environment variables you may have in your profile file. You could solve this by adding them to the top of your crontab file but I prefer to leave that file as simple as possible and create a wrapper script to call instead of rake. Basically the CronRakeTask does the same as Whenever's built in RakeTask except it calls /usr/local/bin/cron_rake instead of rake.
The cron_rake file just sets the environment variables I need then calls rake.
#!/bin/bash export PATH=/usr/local/lib/ruby-enterprise/bin:$PATH export ORACLE_HOME=/opt/oracle export LD_LIBRARY_PATH=/opt/oracle:$LD_LIBRARY_PATH rake $@
As I said in the beginning since I've been using the Whenever gem I no longer need to manually edit my crontab files ever and I can enable my jobs as part of my normal deployment process. Its wonderful and I think everyone should use it!