We will have 'pre' and 'post' functions.
How to deal with stuck / long-running jobs?
+ pre() and post()
+ (instead of cleanup)
+
- We should have instance/timeout settings that allows us to deal
with jobs that run too long:
let job, dir, serial, time = IntMap.find pid !runningmap in
runningmap := IntMap.remove pid !runningmap;
serialmap := BigIntMap.remove serial !serialmap;
- cleanup_job job dir serial time status
+ post_job job dir serial time status
)
with Unix_error _ | Not_found -> ()
-and cleanup_job job dir serial time status =
- (* If there is a cleanup function, run it. *)
- (match job.job_cleanup with
+and post_job job dir serial time status =
+ (* If there is a post function, run it. *)
+ (match job.job_post with
| None -> ()
- | Some cleanup ->
+ | Some post ->
let code =
match status with
| WEXITED c -> c
res_output = dir // "output.txt";
res_start_time = time
} in
- try cleanup result
+ try post result
with
| Failure msg ->
- Syslog.error "job %s cleanup function failed: %s" job.job_name msg
+ Syslog.error "job %s post function failed: %s" job.job_name msg
| exn ->
- Syslog.error "job %s cleanup function exception: %s"
+ Syslog.error "job %s post function exception: %s"
job.job_name (Printexc.to_string exn)
);
let lift_expr = M.Expr.meta_expr
(* Handle a top level statement. *)
-let rec call_stmt name cleanup (_loc, stmt, sh) =
+let rec call_stmt name pre post (_loc, stmt, sh) =
let name =
match name with
| None -> let name = unique_job_name () in <:expr< $str:name$ >>
| Some name -> name in
- let cleanup = expr_of_option _loc cleanup in
+ let pre = expr_of_option _loc pre in
+ let post = expr_of_option _loc post in
match stmt with
- | `When e -> when_stmt _loc name cleanup e sh
- | `Every p -> every_stmt _loc name cleanup p sh
+ | `When e -> when_stmt _loc name pre post e sh
+ | `Every p -> every_stmt _loc name pre post p sh
(* Handle a top level "when" statement.
* e -> when expression
* Returns a top level statement (str_item) which when executed just
* adds the statement to a global list.
*)
-and when_stmt _loc name cleanup e sh =
+and when_stmt _loc name pre post e sh =
let loc = expr_of_loc _loc _loc in
let e = lift_expr _loc e in
<:str_item<
open Camlp4.PreCast
- Whenfile.add_when_job $loc$ $name$ $cleanup$ $e$ $sh$
+ Whenfile.add_when_job $loc$ $name$ $pre$ $post$ $e$ $sh$
>>
(* Handle a top level "every" statement. *)
-and every_stmt _loc name cleanup period sh =
+and every_stmt _loc name pre post period sh =
let loc = expr_of_loc _loc _loc in
<:str_item<
open Camlp4.PreCast
- Whenfile.add_every_job $loc$ $name$ $cleanup$ $period$ $sh$
+ Whenfile.add_every_job $loc$ $name$ $pre$ $post$ $period$ $sh$
>>
let () =
| [ e = period_parser -> e ]
];
- (* Cleanup function. *)
- cleanup: [
- [ "cleanup"; f = expr -> f ]
- ];
+ (* Pre and post functions. *)
+ pre: [[ "pre"; f = expr -> f ]];
+ post: [[ "post"; f = expr -> f ]];
(* Top level statements. *)
statement: [
(* "str_item" is a top level statement in an OCaml program. *)
str_item: LEVEL "top" [
- [ s = statement -> call_stmt None None s ]
+ [ s = statement -> call_stmt None None None s ]
| [ "job"; name = expr;
- cleanup = OPT cleanup;
+ pre = OPT pre;
+ post = OPT post;
s = statement ->
- call_stmt (Some name) cleanup s ]
+ call_stmt (Some name) pre post s ]
];
END
sh_script : string;
}
+type preinfo = {
+ pi_job_name : string;
+ pi_serial : Big_int.big_int;
+}
+
type result = {
res_job_name : string;
res_serial : Big_int.big_int;
res_start_time : float;
}
-type cleanup = result -> unit
+type pre = preinfo -> bool
+type post = result -> unit
type variable =
| T_unit
type job = {
job_loc : Loc.t;
job_name : string;
- job_cleanup : cleanup option;
+ job_pre : pre option;
+ job_post : post option;
job_cond : job_cond;
job_script : shell_script;
}
}
(** A shell script. *)
+type preinfo = {
+ pi_job_name : string; (** Job name. *)
+ pi_serial : Big_int.big_int; (** Job serial number. *)
+}
+(** Information available to pre function before the job runs. *)
+
type result = {
res_job_name : string; (** Job name. *)
res_serial : Big_int.big_int; (** Job serial number. *)
}
(** Result of the run of a job. *)
-type cleanup = result -> unit
-(** A cleanup function. *)
+type pre = preinfo -> bool
+type post = result -> unit
+(** Pre and post functions. *)
type variable =
| T_unit
type job = {
job_loc : Camlp4.PreCast.Loc.t;
job_name : string;
- job_cleanup : cleanup option;
+ job_pre : pre option;
+ job_post : post option;
job_cond : job_cond;
job_script : shell_script;
}
let init s = state := s
-let add_when_job _loc name cleanup e sh =
+let add_when_job _loc name pre post e sh =
let e = expr_of_ast _loc e in
- let job = { job_loc = _loc; job_name = name; job_cleanup = cleanup;
+ let job = { job_loc = _loc; job_name = name;
+ job_pre = pre; job_post = post;
job_cond = When_job e; job_script = sh } in
state := Whenstate.add_job !state job
-let add_every_job _loc name cleanup e sh =
- let job = { job_loc = _loc; job_name = name; job_cleanup = cleanup;
+let add_every_job _loc name pre post e sh =
+ let job = { job_loc = _loc; job_name = name;
+ job_pre = pre; job_post = post;
job_cond = Every_job e; job_script = sh } in
state := Whenstate.add_job !state job
val get_state : unit -> Whenstate.t
(** Return the updated state. Call this after parsing the file. *)
-val add_when_job : Camlp4.PreCast.Loc.t -> string -> Whenexpr.cleanup option -> Camlp4.PreCast.Ast.expr -> Whenexpr.shell_script -> unit
+val add_when_job : Camlp4.PreCast.Loc.t -> string -> Whenexpr.pre option -> Whenexpr.post option -> Camlp4.PreCast.Ast.expr -> Whenexpr.shell_script -> unit
(** When a 'when' macro appears as a toplevel statement in an
input file, it causes this function to be called.
[name] is the name of the job.
- [cleanup] is the optional cleanup function.
+ [pre] and [post] are the optional pre and post functions.
[expr] is the expression, as an OCaml abstract syntax tree.
[sh] is the shell script fragment (basically location + a big string). *)
-val add_every_job : Camlp4.PreCast.Loc.t -> string -> Whenexpr.cleanup option -> Whenexpr.periodexpr -> Whenexpr.shell_script -> unit
+val add_every_job : Camlp4.PreCast.Loc.t -> string -> Whenexpr.pre option -> Whenexpr.post option -> Whenexpr.periodexpr -> Whenexpr.shell_script -> unit
(** When an 'every' macro appears as a toplevel statement in an
input file, it causes this function to be called.
[name] is the name of the job.
- [cleanup] is the optional cleanup function.
+ [pre] and [post] are the optional pre and post functions.
[periodexpr] is the period, eg. 30 seconds.
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*)
-(* Test cleanup functions. *)
+(* Test post functions (used to be called "cleanup functions"). *)
-job "with cleanup"
-cleanup (Whentools.mailto "you@example.com")
+job "with post"
+post (Whentools.mailto "you@example.com")
when true :
<<
# nothing
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
+setting the initial values of variables, or for defining pre and post
functions.
A simple example of an OCaml expression is:
Whentools.set_variable "name" "Richard";
Whentools.set_variable_int "counter" 0
-=head3 CLEANUP FUNCTIONS
+=head3 POST 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 ...>
+writing a C<post> function. To write a post function you have to
+name the job (ie. have an explicit C<job> statement). Put C<post ...>
after the job name like this:
job "poll source"
- cleanup (Whentools.mailto "you@example.com")
+ post (Whentools.mailto "you@example.com")
every 10 seconds :
<<
# ...
>>
-A number of cleanup functions are available in the library; see below.
+A number of post functions are available in the library; see below.
-You can also write your own cleanup functions (in OCaml). The
+You can also write your own post functions (in OCaml). The
function is passed one argument which is a C<Whentools.result> struct,
defined below.
Here are some examples of using the mailto function:
job "ex.1"
- cleanup (Whentools.mailto "you@example.com")
+ post (Whentools.mailto "you@example.com")
every 10 seconds :
<<
# do something
>>
job "ex.2"
- cleanup (Whentools.mailto ~only_on_failure:true
- "you@example.com")
+ post (Whentools.mailto ~only_on_failure:true
+ "you@example.com")
every 10 seconds :
<<
# do something
let to_addr = "you@example.com"
job "ex.3"
- cleanup (Whentools.mailto ~from to_addr)
+ post (Whentools.mailto ~from to_addr)
every 10 seconds :
<<
# do something
=item B<Whentools.result>
-This structure is passed to cleanup functions. It has the following
+This structure is passed to post functions. It has the following
fields:
type result = {