Implement cleanup functions, including 'mailto'.
[whenjobs.git] / tools / whenjobs.pod
index ad60c0d..fd0a6e7 100644 (file)
@@ -396,14 +396,18 @@ ran, then this evaluates to true, else false.
 
 This is the same as writing C<prev variable E<gt> variable>.
 
-B<Note:> There is a subtle and difficult problem with using the
-I<decreases> operator: The first time the expression is evaluated, the
-job has (by definition) not yet run.  Therefore C<prev variable>
-evaluates to C<""> (see definition of I<prev> above).  Since
-C<"" E<lt> everything>, the I<decreases> operator evaluates to
-false, and since this usually means the job does not run, the
-operator always evaluates to false.  A future version of whenjobs
-will address this problem.
+B<Note:> There is a subtle gotcha with the I<decreases> operator: The
+first time the expression is evaluated, the job has (by definition)
+not yet run.  Therefore C<prev variable> evaluates to C<""> (see
+definition of I<prev> above).  Since it is always true that
+
+ "" < anything
+
+the I<decreases> operator evaluates to false, and since this usually
+means the job does not run, the operator always evaluates to false.
+
+To fix this, ensure that the variable is initialized (see
+L</SETTING THE INITIAL VALUE OF VARIABLES> below).
 
 =item B<reloaded ()>
 
@@ -411,9 +415,7 @@ This evaluates to true the first time the expression is evaluated
 after the jobs file has been reloaded or the daemon restarted.
 Thereafter it evaluates to false.
 
-You can use this to initialize variables, but note that this does not
-solve the I<decreases> operator problem described above, because
-variables are initialized too late to affect that.
+Don't use this to initialize variables: it won't do what you mean.
 
 =item B<false>
 
@@ -498,12 +500,177 @@ well-known directory, eg. C<$HOME>, C</var> etc.
 The shell script runs as the ordinary user.  It has no special
 privileges.
 
+=head2 JOB NAMES
+
+Jobs are given implicit names (C<job$1>, C<job$2> etc.).  You can also
+name jobs explicitly by preceeding the "every" or "when" statement
+with C<job "name">:
+
+ job "poll source"
+ every 10 seconds :
+ <<
+   # ...
+ >>
+
+The job name is passed to the shell script in the C<$JOBNAME>
+environment variable.
+
+=head2 OCAML EXPRESSIONS
+
+As well as simple "every" and "when" expressions, advanced users may
+want to use arbitrary OCaml expressions, functions, etc in the jobs
+script.  These are useful for factoring common code or strings, for
+setting the initial values of variables, or for defining cleanup
+functions.
+
+A simple example of an OCaml expression is:
+
+ let prefix = "daily_"
+ job (prefix ^ "virus_scan")
+ every day :
+ <<
+   # ...
+ >>
+ job (prefix ^ "disk_check")
+ every day :
+ <<
+   # ...
+ >>
+
+which creates two jobs called C<"daily_virus_scan"> and
+C<"daily_disk_check"> (C<^> is the OCaml string concatenation
+operator).
+
+OCaml expressions have access to a library of functions called
+B<Whentools> which is described below.  It lets you set variables,
+create jobs algorithmically, etc.
+
+The OCaml expressions run once, when the jobs file is being loaded or
+reloaded.
+
+=head3 SETTING THE INITIAL VALUE OF VARIABLES
+
+Variables are created when they are referenced, and until set they
+have the value empty string (just like the shell).  Across file
+reloads, the previous values of variables is preserved.
+
+To initialize a variable to a known value when the jobs file is
+loaded, call one of the C<Whentools.set_variable*> functions as in
+this example:
+
+ let () =
+   Whentools.set_variable "name" "Richard";
+   Whentools.set_variable_int "counter" 0
+
+=head3 CLEANUP FUNCTIONS
 
+After a job runs, you can control what happens to its output by
+writing a cleanup function.  To write a cleanup function you have to
+name the job (ie. have an explicit C<job> statement).  Put C<cleanup ...>
+after the job name like this:
 
+ job "poll source"
+ cleanup (Whentools.mailto "you@example.com")
+ every 10 seconds :
+ <<
+   # ...
+ >>
+
+A number of cleanup functions are available in the library; see below.
+
+You can also write your own cleanup functions (in OCaml).  The
+function is passed one argument which is a C<Whentools.result> struct,
+defined below.
+
+=head3 WHENTOOLS LIBRARY
+
+=head4 Functions
+
+=over 4
 
+=item B<Whentools.mailto> [I<~only_on_failure:true>]
+[I<~from:from_address>] I<email_address> I<result>
 
+Send the result of the script by email to the given email address.
 
+If the optional C<~only_on_failure:true> flag is set, then it is only
+sent out if the script failed.
 
+If the optional C<~from> flag is set, then the from address is set
+accordingly.  This is sometimes needed when sending mail.
+
+Note the C<result> parameter is passed implicitly by the daemon.  You
+do not need to add it.
+
+Here are some examples of using the mailto function:
+
+ job "ex.1"
+ cleanup (Whentools.mailto "you@example.com")
+ every 10 seconds :
+ <<
+   # do something
+ >>
+
+ job "ex.2"
+ cleanup (Whentools.mailto ~only_on_failure:true
+                           "you@example.com")
+ every 10 seconds :
+ <<
+   # do something
+ >>
+
+ let from = "me@example.com"
+ let to_addr = "you@example.com"
+ job "ex.3"
+ cleanup (Whentools.mailto ~from to_addr)
+ every 10 seconds :
+ <<
+   # do something
+ >>
+
+=item B<Whentools.set_variable> I<name> I<string>
+
+Set variable I<name> to the string.
+
+=item B<Whentools.set_variable_bool> I<name> I<b>
+
+Set variable I<name> to the boolean value I<b>.
+
+=item B<Whentools.set_variable_int> I<name> I<i>
+
+Set variable I<name> to the integer value I<i>.
+
+=item B<Whentools.set_variable_string> I<name> I<s>
+
+Set variable I<name> to the string value <s>.  This is
+the same as I<Whentools.set_variable>.
+
+=item B<Whentools.set_variable_float> I<name> I<f>
+
+Set variable I<name> to the floating point value I<f>.
+
+=back
+
+=head4 Structures
+
+=over 4
+
+=item B<Whentools.result>
+
+This structure is passed to cleanup functions.  It has the following
+fields:
+
+ type result = {
+   res_job_name : string; # job name
+   res_code : int;        # return code from the shell script
+   res_tmpdir : string;   # temporary directory script ran in
+   res_output : string;   # filename of stdout/stderr output
+ }
+
+=back
 
 =head1 FILES