The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Cron - cron-like scheduler for Perl subroutines

SYNOPSIS

  use Schedule::Cron;

  # Subroutines to be called
  sub dispatcher { 
    print "ID:   ",shift,"\n"; 
    print "Args: ","@_","\n";
  }

  sub check_links { 
    # do something... 
  }

  # Create new object with default dispatcher
  my $cron = new Schedule::Cron(\&dispatcher);

  # Load a crontab file
  $cron->load_crontab("/var/spool/cron/perl");

  # Add dynamically  crontab entries
  $cron->add_entry("3 4  * * *",ROTATE => "apache","sendmail");
  $cron->add_entry("0 11 * * Mon-Fri",\&check_links);

  # Run scheduler 
  $cron->run(detach=>1);
                   

DESCRIPTION

This module provides a simple but complete cron like scheduler. I.e this modules can be used for periodically executing Perl subroutines. The dates and parameters for the subroutines to be called are specified with a format known as crontab entry ("METHODS", add_entry() and crontab(5))

The philosophy behind Schedule::Cron is to call subroutines periodically from within one single Perl program instead of letting cron trigger several (possibly different) perl scripts. Everything under one roof. Furthermore Schedule::Cron provides mechanism to create crontab entries dynamically, which isn't that easy with cron.

Schedule::Cron knows about all extensions (well, at least all extensions I'm aware of, i.e those of the so called "Vixie" cron) for crontab entries like ranges including 'steps', specification of month and days of the week by name or coexistence of lists and ranges in the same field. And even a bit more (like lists and ranges with symbolic names).

METHODS

$cron = new Schedule::Cron($dispatcher,[extra args])

Creates a new Cron object. $dispatcher is a reference to a subroutine, which will be called by default. $dispatcher will be invoked with the arguments parameter provided in the crontab entry if no other subroutine is specified. This can be either a single argument containing the argument parameter literally has string (default behavior) or a list of arguments when using the eval option described below.

The date specifications must be either provided via a crontab like file or added explicitly with add_entry() ("add_entry").

extra_args can be a hash or hash reference for additional arguments. The following parameters are recognized:

 file => <crontab>  Load the crontab entries from <crontab>

 eval =>  1         Eval  the argument  parameter in  a crontab
                    entry   before   calling   the   subroutine
                    (instead    of   literally    calling   the
                    dispatcher  with the argument  parameter as
                    string
$cron->load_crontab($file)
$cron->load_crontab(file=>$file,[eval=>1])

Loads and parses the crontab file $file. The entries found in this file will be added to the current time table with $cron->add_entry.

The format of the file consists of cron commands containing of lines with at least 5 columns, whereas the first 5 columns specify the date. The rest of the line (i.e columns 6 and greater) contains the argument with which the dispatcher subroutine will be called. By default, the dispatcher will be called with one single string argument containing the rest of the line literally. Alternatively, if you call this method with the optional argument eval=>1 (you must then use the second format shown above), the rest of the line will be evaled before used as argument for the dispatcher.

For the format of the first 5 columns, please see "add_entry".

Blank lines and lines starting with a # will be ignored.

There's no way to specify another subroutine within the crontab file. All calls will be made to the dispatcher provided at construction time.

If you want to start up fresh, you should call $cron->clean_timetable() before.

Example of a crontab fiqw(le:)

   # The following line runs on every Monday at 2:34 am
   34 2 * * Mon  "make_stats"
   # The next line should be best read in with an eval=>1 argument
   *  * 1 1 *    { NEW_YEAR => '1',HEADACHE => 'on' }
$cron->add_entry($timespec,[arguments])

Adds a new entry to the list of scheduled cron jobs.

Time and Date specification

$timespec is the specification of the scheduled time in crontab format (crontab(5)) which contains five time and date fields. $timespec can be either a plain string, which contains a whitespace separated time and date specification. Alternatively, $timespec can be a reference to an array containing the five elements for the date fields.

The time and date fields are (cited from crontab(5), "Vixie" cron):

   field          values
   =====          ======
   minute         0-59
   hour           0-23
   day of month   1-31 
   month          1-12 (or as names)
   day of week    0-7 (0 or 7 is Sunday, or as names )

 A field may be an asterisk (*), which always stands for
 ``first-last''.

 Ranges of numbers are  allowed.  Ranges are two numbers
 separated  with  a  hyphen.   The  specified  range  is
 inclusive.   For example, 8-11  for an  ``hours'' entry
 specifies execution at hours 8, 9, 10 and 11.

 Lists  are allowed.   A list  is a  set of  numbers (or
 ranges)  separated by  commas.   Examples: ``1,2,5,9'',
 ``0-4,8-12''.

 Step  values can  be used  in conjunction  with ranges.
 Following a range with ``/<number>'' specifies skips of
 the  numbers value  through the  range.   For example,
 ``0-23/2'' can  be used in  the hours field  to specify
 command execution every  other hour (the alternative in
 the V7 standard is ``0,2,4,6,8,10,12,14,16,18,20,22'').
 Steps are  also permitted after an asterisk,  so if you
 want to say ``every two hours'', just use ``*/2''.

 Names can also  be used for the ``month''  and ``day of
 week''  fields.  Use  the  first three  letters of  the
 particular day or month (case doesn't matter).

 Note: The day of a command's execution can be specified
       by two fields  -- day of month, and  day of week.
       If both fields are restricted (ie, aren't *), the
       command will be run when either field matches the
       current  time.  For  example, ``30  4 1,15  * 5''
       would cause a command to be run at 4:30 am on the
       1st and 15th of each month, plus every Friday

In addition, ranges or lists of names are allowed.

Examples:

 "8  0 * * *"       ==> 8 minutes after midnight, every day
 "5 11 * * Sat,Sun" ==> at 11:05 on each Saturday and Sunday
 "0-59/5 * * * *"   ==> every five minutes
 "42 12 3 Feb Sat"  ==> at 12:42 on 3rd of February and on 
                        each Saturday in February

Command specification

The subroutine to be executed when the the $timespec matches can be specified in several ways.

First, if the optional arguments are lacking, the default dispatching subroutine provided at construction time will be called without arguments.

If the second parameter to this method is a reference to a subroutine, this subroutine will be used instead of the dispatcher.

Any additional parameters will be given as arguments to the subroutine to be executed. You can also specify a reference to an array instead of a list of parameters.

You can also use a named parameter list provided as an hashref. The named parameters recognized are:

   subroutine      reference to subroutine to be executed
   sub

   arguments       reference to array containing arguments
   args            to be use when calling the subroutine

   eval            if  set, provide the  subroutine with
                   the  evaled string provided  with the
                   'arguments'      parameter.       The
                   evaluation     will     take    place
                   immediately (not  when the subroutine
                   is to be called)

Examples:

   $cron->add_entry("* * * * *");
   $cron->add_entry("* * * * *","doit");
   $cron->add_entry("* * * * *",\&dispatch,"first",2,"third");
   $cron->add_entry("* * * * *",{'subroutine' => \&dispatch,
                                 'arguments'  => [ "first",2,"third" ]});
   $cron->add_entry("* * * * *",{'subroutine' => \&dispatch,
                                 'arguments'  => '[ "first",2,"third" ]',
                                 'eval'       => 1});
$cron->run([options])

This method starts the scheduler.

When called without options, this method will never return and executes the scheduled subroutine calls as needed.

Alternatively, you can detach the main scheduler loop from the current process (daemon mode). In this case, the pid of the forked scheduler process will be returned.

The options parameter specifies the running mode of Schedule::Cron. It can be either a plain list which will be interpreted as a hash or it can be a reference to a hash. The following named parameters (keys of the provided hash) are recognized:

   detach    if set to one, detach the scheduler process
             from the current process

   pid_file  if  running   in  daemon  mode,   name  the
             optional file,  in which the  process id of
             the scheduler process should be written. By
             default, no PID File will be created.

Examples:

   # Start  scheduler, detach  from current  process and
   # write  the  PID  of  the forked  scheduler  to  the
   # specified file
   $cron->run(detach=>1,pid_file=>"/var/run/scheduler.pid");

   # Start scheduler and wait forever.
   $cron->run();
$cron->clean_timetable()

Remove all scheduled entries

$cron->check_entry($id)

Check, whether the given ID is already registered in the timetable. A ID is the first argument in the argument parameter of the a crontab entry.

Returns (one of) the index in the timetable (can be 0, too) if the ID could be found or undef otherwise.

Example:

   $cron->add_entry("* * * * *","ROTATE");
   .
   .
   defined($cron->check_entry("ROTATE")) || die "No ROTATE entry !"
$cron->get_next_execution_time($cron_entry,[$ref_time])

Well, this is mostly an internal method, but it might be useful on its own.

The purpose of this method is to calculate the next execution time from a specified crontab entry

Parameters:

  $cron_entry  The crontab entry as specified in L<"add_entry">
  $ref_time    the reference time for which the next time should be
               searched which matches $cron_entry. By default, take
               the current time

This method returns the number of epoch-seconds of the next matched date for $cron_entry.

Since I suspect, that this calculation of the next execution time might fail in some circumstances (bugs are lurking everywhere ;-) an additional interactive method bug() is provided for checking crontab entries against your expected output. Refer to the top-level README for additional usage information for this method.

TODO

  • Provide a reload() method for reexaming the crontab file

  • Clean up get_next_execution_time() and give it at least some rational grounding ;-)

  • Provide support for systems without fork() via OS::Process

  • Add logging

COPYRIGHT

Copyright 1999,2000 Roland Huss.

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

AUTHOR

                                                    ...roland