views:

866

answers:

6

Hi,

This keeps happening to me all the time: 1) I write a script(ruby, shell, etc). 2) run it, it works. 3) put it in crontab so it runs in a few minutes so I know it runs from there. 4) It doesnt, no error trace, back to step 2 or 3 a 1000 times.

When I ruby script fails in crontab, I can't really know why it fails cause when I pipe output like this:

ruby script.rb >& /path/to/output

I sorta get the output of the script, but I don't get any of the errors from it and I don't get the errors coming from bash (like if ruby is not found or file isn't there)

I have no idea what environmental variables are set and whether or not it's a problem. Turns out that to run a ruby script from crontab you have to export a ton of environment variables.

Is there a way for me to just have crontab run a script as if I ran it myself from my terminal?

When debugging, I have to reset the timer and go back to waiting. Very time consuming.

How to test things in crontab better or avoid these problems?

A: 

You could write a wrapper script, called for example rbcron, which looks something like:

#!/bin/bash
RUBY=ruby
export VAR1=foo
export VAR2=bar
export VAR3=baz

$RUBY "$*" 2>&1

This will redirect standard error from ruby to the standard output. Then you run rbcron in your cron job, and the standard output contains out+err of ruby, but also the "bash" errors existing from rbcron itself. In your cron entry, redirect 2>&1 > /path/to/output to get output+error messages to go to /path/to/output.

maxwellb
Change VAR1, etc, and values to whatever you need exported for ruby. I don't have these answers.
maxwellb
A: 

If you really want to run it as yourself, you may want to invoke ruby from a shell script that sources your .profile/.bashrc etc. That way it'll pull in your environment.

However, the downside is that it's not isolated from your environment, and if you change that, you may find your cron jobs suddenly stop working.

Brian Agnew
Sourcing .profile/.bashrc will set the same environment variables as those that are set from that file, but will not "fail to isolate from your environment" with respect to the running process, but you are right -- it creates a dependency on a file in your HOME directory.
maxwellb
+2  A: 

Run a 'set' command from inside of the ruby script, fire it from crontab, and you'll see exactly what's set and what's not.

Marcin
+2  A: 

"Is there a way for me to just have crontab run a script as if I ran it myself from my terminal?"

Yes:

bash -li -c /path/to/script

From the man page:

[vindaloo:pgl]:~/p/test $ man bash | grep -A2 -m1 -- -i
   -i        If the -i option is present, the shell is interactive.
   -l        Make bash act as if it had been invoked as a login shell (see
             INVOCATION below).
pgl
Great answer, this is the appropriate way to execute things from a crontab when desiring an environment identical to executing it from a command-line.
Mahmoud Abdelkader
A: 

To find out the environment in which cron runs jobs, add this cron job:

{ echo "\nenv\n" && env|sort ; echo "\nset\n" && set; } | /usr/bin/mailx -s 'my env' [email protected]

Or send the output to a file instead of email.

glenn jackman
+3  A: 

G'day,

One of the basic problems with cron is that you get a minimal environment being set by cron. In fact, you only get four env. var's set and they are:

  • SHELL - set to /bin/sh
  • LOGNAME - set to your userid as found in /etc/passwd
  • HOME - set to your home dir. as found in /etc/passwd
  • PATH - set to "/usr/bin:/bin"

That's it.

However, what you can do is take a snapshot of the environment you want and save that to a file.

Now make your cronjob source a trivial shell script that sources this env. file and then executes your Ruby script.

BTW Having a wrapper source a common env. file is an excellent way to enforce a consistent environment for multiple cronjobs. This also enforces the DRY principle because it gives you just one point to update things as required, instead of having to search through a bunch of scripts and search for a specific string if, say, a logging location is changed or a different utility is now being used, e.g. gnutar instead of vanilla tar.

Actually, this technique is used very successfully with The Build Monkey which is used to implement Continuous Integration for a major software project that is common to several major world airlines. 3,500kSLOC being checked out and built several times a day and over 8,000 regression tests run once a day.

HTH

'Avahappy,

Rob Wells