omegaweaponZ has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,
I have a random question that is bugging me. I have a perl script that uses the Data::ICal::DateTime module to parse out existing ical entries in an ICS local file which is dumped into a sql database. The script works beautiful when run manually, but fails on a cron job. Error log when running state the following error:

"Can't locate object method "events" via package "Class::ReturnValue" at /script.pl line 60.

Line 60 is the code below:

my @events1 = $cal->events($span);
So its somehow thinking I'm using the Class::ReturnValue of the $cal variable instead of the Data::ICal module, but again, this only happens on the crontab, manual launch works fine. I have various other modules on other scripts that work fine on a crontab, but this is the only one that has failed. No special formatting or directory changes occur here...so I'm stumped. Any ideas? Please see sample script below:

#!/usr/bin/perl use strict; use Data::ICal::DateTime; my $date1 = DateTime->new( year => 2012); my $date2 = DateTime->new( year => 2013); my $span = DateTime::Span->from_datetimes( start => $date1, end => $d +ate2 ); my $cal = Data::ICal->new(filename => 'Calendar.ics'); my @events1 = $cal->events($span); foreach my $event (@events1) { my $summary = $event->summary; my $start = $event->start; my $end = $event->end; # Continue sql insertion next...

Replies are listed 'Best First'.
Re: perl module not working in crontab
by ikegami (Patriarch) on Jan 03, 2012 at 01:24 UTC

    Ignore what others say about @INC and PERL5LIB. It's not a problem loading Class::ReturnValue.

    The docs say:

    Returns a false value upon failure to open or parse the file or data; this false value is a Class::ReturnValue object and can be queried as to its error_message.

    so

    my $cal = Data::ICal->new(filename => 'Calendar.ics');

    should be

    my $cal = Data::ICal->new(filename => 'Calendar.ics'); die "Can't open calendar: ".$cal->error_message()."\n" if !$cal;

    I bet you'll the problem is that your script can't find Calendar.ics because the current directory isn't what you assume it to be.

      Ahhh!!! You rock. I can't believe I didn't catch that, nice job. And that's why I post the full script :)

        Always that a script fail in your crontab, check 'env' output before launch it (and compare both (inside crontab and outside)), like ikegami says, this time CWD var has the reason of failure

Re: perl module not working in crontab
by toolic (Bishop) on Jan 03, 2012 at 01:00 UTC
    If you have multiple versions of perl installed, you may need to use the full path to your perl executable in your crontab file:
    /full/path/to/my/perl my_script.pl
    Different version of perl have potentially different module include paths (@INC).

    super search where title contains "crontab"

Re: perl module not working in crontab
by JavaFan (Canon) on Jan 03, 2012 at 00:57 UTC
    Hmmm, why do you post the first 15 lines of your script, if the error occurs at line 60?

    Anyway, it's probably that you're depending on some environment variable, which is set in your shell, but not from crontab. PERL5LIB comes to mind. Or it's PATH, and you're running a different perl.

Re: perl module not working in crontab
by Anonymous Monk on Jan 03, 2012 at 00:50 UTC
    Dumper and compare @INC/%INC
Re: perl module not working in crontab
by omegaweaponZ (Beadle) on Jan 03, 2012 at 01:17 UTC
    same perl installation, only one installed. @INC looks fine, same path as normal and includes where the module is installed. is there anyway I can specifically set the crontab to pull all modules it uses directly from the folder where the modules are installed? either within the crontab or in the script itself...
Re: perl module not working in crontab
by locked_user sundialsvc4 (Abbot) on Jan 03, 2012 at 14:58 UTC

    Remember that a cron-job is run by a daemon that probably runs as nobody, and that it will run in as “pristine” an environment as possible.   Therefore, what I normally do is to run a stub shell-script which in turn invokes a stub Perl-program.   For example:

    myjob.sh:

    #!/usr/bin/bash /usr/bin/perl /path/to/somewhere/cronstub.pl

    cronstub.pl:   (Note:   I’m just makin’ this stuff up on the fly ...)

    #!/usr/bin/perl use strict; use warnings; use lib qw(/path/to/where/everything/lives); use main_module; exec { main_module(); return 0; } if ($@) { print STDERR "Cron job failed: $@\n"; return -1; }

    Notice:   (and many of these are just my personal idiosyncrasies ...)

    1. Everything is explicit.   Path names to everything including Perl are spelled-out.
      • You’re absolutely right that, if anything changes, you’ll have to change the cron-job.   (Don’t forget to check-in the revised version back into the version-control system ...)
      • If you have many such jobs, make it easy on yourself and adopt a consistent side-wide standard modus operandi.)
    2. The stub uses a use lib statement, not a dependency on $PERL5LIB, to specify where the application lives.   It then uses the application main module and invokes it.   At this point, the main-program should be running in whatever is its “proper” environment, cron or not.
    3. The stub Perl program sets a meaningful return-code value.   It traps runtime errors, reports them if they occur, and sets a sentinel return-code value.