I installed and configured RVM roughly following the pattern outlined in the first part of this set of instructions: http://blog.ninjahideout.com/posts/a-guide-to-a-nginx-passenger-and-rvm-server
Basically, this means there is no pre-build system ruby (all ruby installs are RVM-managed) and RVM is installed system-wide instead of attached to a particular user (files at /usr/local/rvm
) so all users in the rvm
group can access the same rubies with the same installed gems.
One issue with setting up the system this way is that the rvm environment must be set up in a shell session before ruby can be used. For all rvm users, I put this in their .bashrc: source "/usr/local/rvm/scripts/rvm"
. This works fine for ssh sessions.
The problem comes in play for cron jobs, which don't execute .bashrc. The rvm script above (/usr/local/rvm/scripts/rvm) is considerably more complicated than setting up a few environment variables, so I'd actually like to run this command prior to every job in the file.
Sure, I could do that manually, like so:
1 2 * * * source "/usr/local/rvm/scripts/rvm"; /do/some/cron/job/1
3 4 * * * source "/usr/local/rvm/scripts/rvm"; /do/some/cron/job/2
5 6 * * * source "/usr/local/rvm/scripts/rvm"; /do/some/cron/job/3
7 8 * * * source "/usr/local/rvm/scripts/rvm"; /do/some/cron/job/4
But I'd prefer to do something like this:
[execute] source "/usr/local/rvm/scripts/rvm"
1 2 * * * /do/some/cron/job/1
3 4 * * * /do/some/cron/job/2
5 6 * * * /do/some/cron/job/3
7 8 * * * /do/some/cron/job/4
Obviously, the above syntax doesn't work. But, is there some way to get this to work? The cron man pages and documentation were not of much help here. But is there some trick or standard way to achieve this?
If it matters, I'm running Ubuntu 10.10 (Maverick Meerkat).
You don't need to write wrappers (following that logic, you might as well write a wrapper to the wrapper). Please keep things simple. All you need to do is configure your cron job to launch a bash shell, and make that bash shell load your environment.
The shebang line in your script should not refer directly to a ruby executable, but to rvm's ruby:
#!/usr/bin/env ruby
This instructs the script to load the environment and run ruby as we would on the command line with rvm loaded.
On many UNIX derived systems, crontabs can have a configuration section before the actual lines that define the jobs to be run. If this is the case, you would then specify:
SHELL=/path/to/bash
This will ensure that the cron job will be spawned from bash. Still, your environment is missing, so to instruct bash to load your environment, you will want to add to the configuration section the following:
BASH_ENV=/path/to/environment (typically .bash_profile or .bashrc)
HOME is automatically derived from the /etc/passwd line of the crontab owner, but you can override it.
HOME=/path/to/home
After this, a cron job might look like this:
15 14 1 * * $HOME/rvm_script.rb
What if your crontab doesn't support the configuration section? Well, you will have to give all the environment directives in one line, with the job itself. For example,
15 14 1 * * export BASH_ENV=/path/to/environment && /full/path/to/bash -c '/full/path/to/rvm_script.rb'
Full blog post on the subject
Just do rvm cron setup
This let's rvm setup ruby cron settings
Then crontab -e
Add your cron tasks, save and close and you are good to go!!
Crontab files generally only allow two types of things (plus comments and blank lines if you want to be pedantic):
- Environment variable setting.
- Command specifications.
And some crontabs don't even support setting environment variables (although I doubt you'll come across such a thing practice).
If you need to do more than set some environment variables then you're going to need to put your source "/usr/local/rvm/scripts/rvm"
either in the cron specs as you have in your question or you'll need to wrap your cron jobs in a cron runner something like this:
#!/bin/sh
source "/usr/local/rvm/scripts/rvm"
exec $1
And then in the crontab:
1 2 * * * /path/rvm_cron_runner /do/some/cron/job/1
Six of one, half a dozen of the other.
If your cronjob is a straight ruby file, the docs say you can just use the built-in wrapper which will load up the correct ruby version and gemset:
1 0 * * * /usr/local/rvm/bin/ruby-1.9.2-p290@projectX /path/to/script.rb
You would still need to add this call to each line however.