Configuring rake tasks with 'whenever' and using app specific rvm settings (.rvmrc)
There's a thorn waiting for you if you decide to schedule your rake tasks using cron if you chose to manage you ruby and gems installs with rvm on an app by app configuration.
'Whenever' already does the heavy lifting, but out-of-the-box it still won't work 'cos when cron fires a rake task you'll get a "Could not find bundler" error. A bit annoying... It sounds as if the rvm environment isn't set. And it's not!
The 'whenever' github project says:
"All jobs are by default run with bash -l -c 'command...'. Among other things, this allows your cron jobs to play nice with RVM by loading the entire environment instead of cron's somewhat limited environment."
And that's fine and all, but if it is so, why are we still getting those errors?
After going through the bash specification it became clear that the rvm "magic" that loads the gemset when you're inside your app directory couldn't happen because running bash -l gives you a login shell that won't fire all the bash configuration files you use when you open a terminal. For that you need the 'interactive' shell, or in another words you need to run it as bash -l -i.
But I haven't yet answered WHY you need it.
This is why:
When you install rvm you need to "Load RVM into your shell sessions as a function", you can see that in the rvm install page.
What this means is that you need to add a script line to one of you bash configuration files. They recommend .bash_profile and the script is:
[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm"
So, in order to have this when running a cron task you have 2 choices:
- Include the script on your task list of commands (messy and cumbersome)
- Run bash in interactive mode (clean and transparent, although eventually slower due to the overhead)
If you don't want to get your hands dirty on the output of 'whenever', I suggest you define the whenever's path and job template and place it on the schedule.rb file:
env 'PATH', ENV['PATH']
set :job_template, "bash -l -i -c ':job'"
Then run whenever --update-crontab
And you're done!


