Search code examples
rvmcron

Need to set up rvm environment prior to every cron job


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).


Solution

  • 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