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

I have a script that I need to run for two hours during the day. I know how to use cron to start the script, but is there anyway to use cron to stop the script at the two hour mark?

The script grabs data from the web and updates a db. The script doesn't know when to start or stop. It just has an infinite loop that keeps grabbing the data so I can't stop the script from within itself.

Thanks.

Replies are listed 'Best First'.
Re: Cron Question
by Fastolfe (Vicar) on Nov 08, 2001 at 03:32 UTC

    Use alarm within your script to schedule a signal, and have your $SIG{ALRM} handler clean up and exit gracefully.

    $SIG{ALRM} = sub { exit; }; alarm 60 * 60 * 2;

    Another option is to have your script write a pid file out someplace:

    open(F, ">$wherever/myscript.pid") or warn "myscript.pid: $!\n"; print F "$$\n"; close(F); $SIG{TERM} = sub { exit; }; END { unlink "$wherever/myscript.pid"; }

    And then script something like this in cron:

    [ -r $wherever/myscript.pid ] && kill `cat $wherever/myscript.pid`
Re: Cron Question
by monkfish (Pilgrim) on Nov 08, 2001 at 04:15 UTC
    As other responses have indicatated cron may not be the best solution but you want to use it here is how you could do it...

    Schedule it to start at some time say 1:30pm with a cron entry like the following:

    13 30 * * * /path/to/myscript.pl

    Have the program print the pid (available in perl as the var $$) to a file like /tmp/myscript.pid and add a second line to cron like:

    15 30 * * * kill `cat /tmp/myscript.pid`
    To kill the app 2 hour later at 3:30pm. Of course you could make the kill fancier if you didn't want an error if the script had finished running...

    In case you were not aware you edit cron with the command crontab -e. See man crontab for more details.

    -monkfish (The Fishy Monk)

      An important administration sanity tip.

      You don't want to edit crons with crontab -e. If someone messes up your cron, you really, really, really need to be able to fix it.

      Instead do:

      crontab cron.ctl
      where cron.ctl is a file you have in a revision control system. Make all edits through editing cron.ctl then reloading the cron.
        I've found that a daily snapshot of current crontabs (in /var/spool/cron/$USER on my linux machine) works fine. Either an automatic cvs check in, or just a tar.gz of modified crontabs. I don't necessarily need an archive of each minor edit made to a crontab during the day, but rolling it back to "the way it worked yesterday" is oft requested.

        Behind the scenes, crontab -e really just automates these two steps:

        vi $DefaultCrontabFile; # use your $EDITOR to edit default file crontab $DefaultCrontabFile; # install said file

        -Blake

Re: Cron Question
by lestrrat (Deacon) on Nov 08, 2001 at 03:58 UTC

    If it's in a loop, can't you do this?

    my $start = time(); while( time() <= $start + 7200 ) { ....sutff.... }

    granted, it consumes some cycles... I'm just weary of using SIGALRM and such. Take it as a TMTOWTDI :-)

      Sidestepping the wisdom of time based loops.....

      Your $start assignment is unnecessary. The special $^T variable already contains that information. (i.e. perl stores the time() value at startup in $^T) So, you could rewrite the above as:

      while ( time-$^T <= 7200 ) { ....sutff.... }
      Note: this is a mod_perl gotcha since the "startup" time could be a looong time ago. $^T is also the value used when the -M, -A, and -C filetest operators determine the relative age of a file. The age is relative to whatever happens to be in $^T, which has implications for any long running perl program.

      -Blake

        Well, it depends on the semantics of the code :-)

        I *usually* want to have the loop to last for X amount of time, and not the script itself. That's where my

        my $start = time()

        ...comes in. And as you said, $^T is sometimes a problem. I like explicit-ness :-)

Re (tilly) 1: Cron Question
by tilly (Archbishop) on Nov 08, 2001 at 05:45 UTC
    The simplest solution is to have the script run the loop once. Then in your crontab do something like:
    * 14-16/5 * * 1-5 your/command
    That will start your script every 5 minutes, on the minute, from 2-4 PM on Monday through Friday.