X-Git-Url: http://git.annexia.org/?p=whenjobs.git;a=blobdiff_plain;f=tools%2Fwhenjobs.pod;h=14ca14134a39e0880e50520aaeb37665a2b8c956;hp=ad60c0db7848f551f12bbf100da32cb0d24e7341;hb=ff2670fcc7fe0b62a44dce15272b7cb362256e05;hpb=5c7aa66dbdb32b4fc11d0f72a4cc028c7bfb1b55 diff --git a/tools/whenjobs.pod b/tools/whenjobs.pod index ad60c0d..14ca141 100644 --- a/tools/whenjobs.pod +++ b/tools/whenjobs.pod @@ -14,7 +14,7 @@ Editing the jobs script: Get and set variables: whenjobs --get variable - whenjobs --set variable value [--type bool|int|float|string] + whenjobs --set variable=value [variable=value ...] whenjobs --variables Start and stop the per-user daemon: @@ -24,6 +24,13 @@ Start and stop the per-user daemon: whenjobs --daemon-status whenjobs --daemon-restart +Examine running jobs: + + whenjobs --jobs + whenjobs --cancel serial + whenjobs --start "name" + whenjobs --tail serial + =head1 DESCRIPTION Whenjobs is a powerful but simple replacement for cron. It lets you @@ -36,7 +43,7 @@ Periodic jobs are written like this: << # Get the current load average. load=`awk '{print $1}' /proc/loadavg` - whenjobs --set load $load --type float + whenjobs --set --type float load=$load >> When-statements let you create jobs that run based on variables set @@ -72,17 +79,54 @@ Variables are stored (per-user) in the daemon. You can use the command line tool to examine and set variables: $ whenjobs --variables - load=0.9 - $ whenjobs --set cat sushi + JOBSERIAL=297 + libguestfs_build_local=1.17.16 + libguestfs_commit=7e32d892d76a31f55e2a4151902623b9949e3efa + libguestfs_dist=1.17.16 + libguestfs_release=1.17.16 + libguestfs_stable_build_local=1.16.10 + libguestfs_stable_commit=27433a0a335301441b1eb6244ba425c2c44b2d99 + libguestfs_stable_dist=1.16.10 + libguestfs_stable_release=1.16.10 + libguestfs_stable_version=1.16.10 + libguestfs_version=1.17.16 + $ whenjobs --set cat=sushi $ whenjobs --get cat sushi -The act of setting a variable (using I<--set>) can trigger jobs to run. +Note: The act of setting a variable (using I<--set>) can trigger jobs +to run. + +You can also list out what jobs are running: + + $ whenjobs --jobs + 287 libguestfs-stable: fedora 16 + running in: /tmp/whenjobsa2afc44fd757465f95438309f1a51609 + started at: 2012-03-13 10:59:37 + +and you can 'tail' the output of running jobs which is useful for +debugging: + + $ whenjobs --tail 287 + Uploading: 147496271972717053d46b82a07435ca libguestfs-1.16.10.tar.gz + +You can start and cancel jobs manually: + + $ whenjobs --start 'libguestfs: poll' + $ whenjobs --cancel 287 =head1 OPTIONS =over 4 +=item B<--cancel> serial + +Cancel the job with the given serial number. + +Use I<--jobs> to list running jobs along with their serial numbers. +The serial number is also available in the job script (as +C<$JOBSERIAL>) and in the log file. + =item B<--daemon-start> =item B<--daemon-stop> @@ -112,6 +156,24 @@ C is used. Print the value of a variable. +=item B<-help> + +=item B<--help> + +Display brief usage and exit. + +=item B<--job-names> + +List the names of all loaded jobs (whether they are running or not). +Use I<--jobs> to list running jobs. + +=item B<--jobs> + +List all running jobs. + +Note that it is possible for the same job to be running more than once +(for example, a periodic job that takes longer than the period to run). + =item B<-l> =item B<--list> @@ -128,7 +190,7 @@ source, eg: whenjobs --lib $builddir/lib -e -=item B<--set> variable value +=item B<--set> variable=value [variable=value ...] =item B<--type> bool|int|float|string|unit @@ -136,18 +198,58 @@ I<--set> sets the variable named C to the new C. The variable is created if it does not already exist. Note that setting a variable can cause jobs to run immediately. -To unset a variable, set it to the empty string: +To unset a variable, set it to the empty string like this: - whenjobs --set var "" + whenjobs --set var= By default variables are strings. You can also set the type of a -variable when setting it by adding the optional I<--type> parameter: +variable when setting it by adding the optional I<--type> parameter. +The I<--type> parameter should come I the variable +declaration, like this: - whenjobs --set free_space 10000 --type int + whenjobs --set --type int free_space=10000 See the discussion of variable types in the L section below. +You can set multiple variables. When setting multiple variables in a +single command, the values are all changed in a single atomic +operation. + + whenjobs --set cat=sushi food=fish + +When using I<--type> and multiple variables, the type changes the +remaining command line parameters until the next I<--type>, eg: + + whenjobs --set cat=sushi \ + --type float weight=3.5 \ + --type string food=fish + +(C and C are strings, and C is a float). + +=item B<--start> "job name" + +Start the job immediately and unconditionally. + +This runs the job even if its normal preconditions are not met. This +may cause unexpected results, so use with caution. + +=item B<--tail> serial + +Tail the output of the running job identified by its serial number. +Use the I<--jobs> flag to get a list of running jobs. + +=item B<--test> variable=value [variable=value ...] + +This works the same way as the I<--set> option, but the difference is +that the variables are not set. Instead, it lists out the jobs that +I run, I the variables were updated to these new values. + +The variables are not actually updated, and the jobs are not actually +run. + +The output is a list of job names that would run. + =item B<--upload> Compile the jobs script and upload it to the daemon, without editing. @@ -165,12 +267,6 @@ Display all the variables and their values, in the format C. Display the name and version of the program and exit. -=item B<-help> - -=item B<--help> - -Display brief usage and exit. - =back =head1 REFERENCE @@ -375,6 +471,11 @@ that it had last time this when-job ran. If the when-job has not run yet, then this returns C<"">. +Job state is preserved across file reloads, but I for jobs that +are explicitly named. If you find that jobs using C, C +etc are running unnecessarily when the jobs file is edited or +uploaded, try giving the jobs an explicit name. + =item B I If the named variable has changed since this job last ran, then this @@ -396,14 +497,18 @@ ran, then this evaluates to true, else false. This is the same as writing C variable>. -B There is a subtle and difficult problem with using the -I operator: The first time the expression is evaluated, the -job has (by definition) not yet run. Therefore C -evaluates to C<""> (see definition of I above). Since -C<"" E everything>, the I 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 There is a subtle gotcha with the I operator: The +first time the expression is evaluated, the job has (by definition) +not yet run. Therefore C evaluates to C<""> (see +definition of I above). Since it is always true that + + "" < anything + +the I 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 below). =item B @@ -411,9 +516,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 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 @@ -498,12 +601,245 @@ well-known directory, eg. C<$HOME>, C etc. The shell script runs as the ordinary user. It has no special privileges. +=head2 JOB NAMES + +Jobs are given implicit names (C, C etc.). You can also +name jobs explicitly by preceeding the "every" or "when" statement +with C: + + 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 pre and post +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 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 are preserved. +To initialize a variable to a known value when the jobs file is +loaded, call one of the C functions as in +this example: + let () = + Whentools.set_variable "name" "Richard"; + Whentools.set_variable_int "counter" 0 + +=head3 PRE FUNCTIONS + +Before a job runs, you can arrange that a C
 function is called.
+This function may decide not to run the job (by returning C).
+
+One use for this is to prevent a particular job from running if there
+is already an instance of the same job running:
+
+ job "only one"
+ pre (Whentools.one ())
+ every 10 seconds :
+ <<
+   # Takes longer than 10 seconds to run, but 'Whentools.one ()'
+   # will ensure only one is ever running.
+   sleep 11
+ >>
+
+When using pre functions, jobs must be given an explicit name, ie.
+you must use the C statement.
+
+A number of pre functions are available in the library; see below.
+
+You can also write your own post functions (in OCaml).  The function
+is passed one argument which is a C struct, defined
+below.  It should return a boolean: C if the job should run, and
+C if the job should not run.
+
+Note that a fresh serial number (see L) is assigned to
+each run, whether or not the job actually runs because of
+preconditions.
+
+=head3 POST FUNCTIONS
+
+After a job runs, you can control what happens to its output by
+writing a C function.  To write a post function you have to
+name the job (ie. have an explicit C statement).  Put C
+after the job name like this:
+
+ job "poll source"
+ post (Whentools.mailto "you@example.com")
+ every 10 seconds :
+ <<
+   # ...
+ >>
+
+A number of post functions are available in the library; see below.
+
+You can also write your own post functions (in OCaml).  The
+function is passed one argument which is a C struct,
+defined below.
+
+=head3 WHENTOOLS LIBRARY
+
+=head4 Functions
+
+=over 4
+
+=item B [I<~only_on_failure:true>]
+[I<~from:from_address>] I I
+
+This built-in post function sends 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 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"
+ post (Whentools.mailto "you@example.com")
+ every 10 seconds :
+ <<
+   # do something
+ >>
+
+ job "ex.2"
+ post (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"
+ post (Whentools.mailto ~from to_addr)
+ every 10 seconds :
+ <<
+   # do something
+ >>
+
+=item B I
+
+This built-in pre function ensures that a maximum of I instances of
+the job are running.
+
+It checks the list of running jobs, and if I or more instances are
+already running, then it returns C, which ensures that the new
+job is not started.
+
+=item B I<()>
+
+This built-in pre function ensures that only one instance of the job
+is running.  It is the same as calling:
+
+ Whentools.max 1
+
+=item B I I
+
+Set variable I to the string.
+
+=item B I I
+
+Set variable I to the boolean value I.
+
+=item B I I
+
+Set variable I to the integer value I.
+
+=item B I I
+
+Set variable I to the string value .  This is
+the same as I.
+
+=item B I I
+
+Set variable I to the floating point value I.
+
+=back
+
+=head4 Structures
+
+=over 4
+
+=item B
+
+This structure is passed to pre functions.  It has the following
+fields:
+
+ type preinfo = {
+   pi_job_name : string;           # Job name.
+   pi_serial : Big_int.big_int;    # Job serial number.
+   pi_variables : (string * variable) list; # Variables set in job.
+   pi_running : preinfo_running_job list;   # List of running jobs.
+ }
+ and preinfo_running_job = {
+   pirun_job_name : string;        # Running job name.
+   pirun_serial : Big_int.big_int; # Running job serial number.
+   pirun_start_time : float;       # Running job start time.
+   pirun_pid : int;                # Running job process ID.
+ }
+
+=item B
+
+This structure is passed to post functions.  It has the following
+fields:
+
+ type result = {
+   res_job_name : string;  # job name
+   res_serial : big_int;   # job serial (same as $JOBSERIAL)
+   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
+   res_start_time : float; # when the job started
+ }
+
+=back
 
 =head1 FILES