module Monitor:sig..end
One can listen to a monitor using Monitor.errors to learn when the monitor sees an error.
If a computation raises an unhandled exception, the current monitor does one of two things. If anyone is listening to the monitor (i.e. Monitor.errors has been called on the monitor), then the error stream is extended, and the listeners are responsible for doing something. If no one is "listening" to the monitor, then the exception is raised to monitor's parent. The initial monitor, i.e. the root of the monitor tree, prints an unhandled-exception message and calls exit 1.
**************** NOTE ABOUT THE TOPLEVEL MONITOR ****************
It is important to note that in the toplevel monitor, exceptions will only be caught in the async part of a computation. For example, in:
upon (f ()) g
if f raises, the exception will not go to a monitor; it will go to the next caml
exception handler on the stack. Any exceptions raised by g will be caught by the
scheduler and propagated to the toplevel monitor. Because of this it is advised to
always use Scheduler.schedule or Scheduler.within. For example:
Scheduler.within (fun () -> upon (f ()) g)
This code will catch an exception in either f or g, and propagate it to the
monitor.
This is only relevant to the toplevel monitor because if you create another monitor
and you wish to run code within it you have no choice but to use Scheduler.within.
try_with creates its own monitor and uses Scheduler.within, so it does not have
this problem.
typet =Raw_monitor.t
type'awith_optional_monitor_name =?here:Core.Std.Source_code_position.t ->
?info:Core.Std.Info.t -> ?name:string -> 'a
val create : (unit -> t) with_optional_monitor_namecreate () returns a new monitor whose parent is the current monitor.val name : t -> Core.Std.Info.tname t returns the name of the monitor, or a unique id if no name was supplied to
create.val current : unit -> tcurrent () returns the current monitorval errors : t -> exn Tail.Stream.terrors t returns a stream of all subsequent errors that monitor t sees.val error : t -> exn Deferred.terror t returns a deferred that becomes defined if the monitor ever sees an error.
Calling error t does not count as "listening for errors", and if no one has called
errors t to listen, then errors will still be raised up the monitor tree.val extract_exn : exn -> exnextract_exn exn extracts the exn from an error exn that comes from a monitor. If it
is not supplied such an error exn, it returns the exn itself.val has_seen_error : t -> boolhas_seen_error t returns true iff the monitor has ever seen an error.val send_exn : t -> ?backtrace:[ `Get | `This of string ] -> exn -> unitsend_exn t exn ?backtrace sends the exception exn as an error to be handled
monitor t. By default, the error will not contain a backtrace. However, the caller
can supply one using `This, or use `Get to request that send_exn obtain one
using Exn.backtrace ().val try_with : (?extract_exn:bool ->
?run:[ `Now | `Schedule ] ->
?rest:[ `Ignore | `Raise ] ->
(unit -> 'a Deferred.t) -> ('a, exn) Core.Std.Result.t Deferred.t)
with_optional_monitor_nametry_with f runs f () in a monitor and returns the result as Ok x if f finishes
normally, or returns Error e if there is some error. It either runs f now, if
run = `Now, or schedules a job to run f, if run = `Schedule. Once a result is
returned, the rest of the errors raised by f are ignored or re-raised, as per
rest. try_with never raises synchronously, and may only raise asynchronously with
rest = `Raise.
The name argument is used to give a name to the monitor the computation will be
running in. This name will appear when printing errors.
If extract_exn = true, then in an Error exn result, the exn will be the actual
exception raised by the computation. If extract_exn = false, then the exn will
include additional information, like the monitor and backtrace. One typically wants
extract_exn = false due to the additional information. However, sometimes one wants
the concision of extract_exn = true.
val try_with_rest_handling : [ `Default of [ `Ignore | `Raise ] | `Force of [ `Ignore | `Raise ] ]
Pervasives.reftry_with_rest_handling determines how try_with f ~rest determines the rest value
it actually uses. If !try_with_rest_handling = `Default d, then d is the default
value for rest, but can be overriden by supplying rest to try_with. If
!try_with_rest_handling = Force f, then the rest supplied to try_with is not
used, and f is.
Initially, !try_with_rest_handling = `Default `Ignore.
val try_with_ignored_exn_handling : [ `Eprintf | `Ignore | `Run of exn -> unit ] Pervasives.reftry_with_ignored_exn_handling describes what should happen when try_with's rest
value is `Ignore, as determined by !try_with_rest_handling and the ~rest
supplied to try_with.
Initially, !try_with_ignored_exn_handling = `Ignore.
val handle_errors : ((unit -> 'a Deferred.t) -> (exn -> unit) -> 'a Deferred.t)
with_optional_monitor_namehandle_errors ?name f handler runs f () inside a new monitor with the optionally
supplied name, and calls handler error on every error raised to that monitor. Any
error raised by handler goes to the monitor in effect when handle_errors was
called.val catch_stream : ((unit -> unit) -> exn Tail.Stream.t) with_optional_monitor_namecatch_stream ?name f runs f () inside a new monitor m and returns the stream of
errors raised to m.val catch : ((unit -> unit) -> exn Deferred.t) with_optional_monitor_namecatch ?name f runs f () inside a new monitor m and returns the first error
raised to m.val protect : ((unit -> 'a Deferred.t) ->
finally:(unit -> unit Deferred.t) -> 'a Deferred.t)
with_optional_monitor_nameprotect f ~finally runs f () and then finally regardless of the success or
failure of f. It re-raises any exception thrown by f or returns whatever f
returned.
The name argument is used to give a name to the monitor the computation will be
running in. This name will appear when printing the errors.
val main : tval kill : t -> unitkill t causes t and all of t's descendants to never start another job. The job
that calls kill will complete, even if it is a descendant of t.
kill can break user expectations. For example, users expect in protect f ~finally
that finally will eventually run. However, if the monitor in which finally would
run is killed, then finally will never run.
val is_alive : t -> boolis_alive t returns true iff none of t or its ancestors have been killed.module Exported_for_scheduler:sig..end
val sexp_of_t : t -> Sexplib.Sexp.tcreate () returns a new monitor whose parent is the current monitor.name t returns the name of the monitor, or a unique id if no name was supplied to
create.current () returns the current monitorerrors t returns a stream of all subsequent errors that monitor t sees.error t returns a deferred that becomes defined if the monitor ever sees an error.
Calling error t does not count as "listening for errors", and if no one has called
errors t to listen, then errors will still be raised up the monitor tree.extract_exn exn extracts the exn from an error exn that comes from a monitor. If it
is not supplied such an error exn, it returns the exn itself.has_seen_error t returns true iff the monitor has ever seen an error.send_exn t exn ?backtrace sends the exception exn as an error to be handled
monitor t. By default, the error will not contain a backtrace. However, the caller
can supply one using `This, or use `Get to request that send_exn obtain one
using Exn.backtrace ().try_with f runs f () in a monitor and returns the result as Ok x if f finishes
normally, or returns Error e if there is some error. It either runs f now, if
run = `Now, or schedules a job to run f, if run = `Schedule. Once a result is
returned, the rest of the errors raised by f are ignored or re-raised, as per
rest. try_with never raises synchronously, and may only raise asynchronously with
rest = `Raise.
The name argument is used to give a name to the monitor the computation will be
running in. This name will appear when printing errors.
If extract_exn = true, then in an Error exn result, the exn will be the actual
exception raised by the computation. If extract_exn = false, then the exn will
include additional information, like the monitor and backtrace. One typically wants
extract_exn = false due to the additional information. However, sometimes one wants
the concision of extract_exn = true.
try_with_rest_handling determines how try_with f ~rest determines the rest value
it actually uses. If !try_with_rest_handling = `Default d, then d is the default
value for rest, but can be overriden by supplying rest to try_with. If
!try_with_rest_handling = Force f, then the rest supplied to try_with is not
used, and f is.
Initially, !try_with_rest_handling = `Default `Ignore.
try_with_ignored_exn_handling describes what should happen when try_with's rest
value is `Ignore, as determined by !try_with_rest_handling and the ~rest
supplied to try_with.
Initially, !try_with_ignored_exn_handling = `Ignore.
handle_errors ?name f handler runs f () inside a new monitor with the optionally
supplied name, and calls handler error on every error raised to that monitor. Any
error raised by handler goes to the monitor in effect when handle_errors was
called.
catch_stream ?name f runs f () inside a new monitor m and returns the stream of
errors raised to m.
catch ?name f runs f () inside a new monitor m and returns the first error
raised to m.
protect f ~finally runs f () and then finally regardless of the success or
failure of f. It re-raises any exception thrown by f or returns whatever f
returned.
The name argument is used to give a name to the monitor the computation will be
running in. This name will appear when printing the errors.
kill t causes t and all of t's descendants to never start another job. The job
that calls kill will complete, even if it is a descendant of t.
kill can break user expectations. For example, users expect in protect f ~finally
that finally will eventually run. However, if the monitor in which finally would
run is killed, then finally will never run.
is_alive t returns true iff none of t or its ancestors have been killed.