Module Clock.Event
Events provide variants of run_at
and run_after
with the ability to abort or reschedule an event that hasn't yet happened. Once an event happens or is aborted, Async doesn't use any space for tracking it.
val sexp_of_t : ('a -> Ppx_sexp_conv_lib.Sexp.t) -> ('h -> Ppx_sexp_conv_lib.Sexp.t) -> ('a, 'h) t -> Ppx_sexp_conv_lib.Sexp.t
type t_unit
= (unit, unit) t
val sexp_of_t_unit : t_unit -> Ppx_sexp_conv_lib.Sexp.t
include Core_kernel.Invariant.S2 with type ('a, 'b) t := ('a, 'b) t
val invariant : 'a Base__.Invariant_intf.inv -> 'b Base__.Invariant_intf.inv -> ('a, 'b) t Base__.Invariant_intf.inv
module Status : sig ... end
val status : ('a, 'h) t -> ('a, 'h) Status.t
If
status
returnsScheduled_at time
, it is possible thattime < Time.now ()
if Async's scheduler hasn't yet gotten the chance to update its clock, e.g., due to user jobs running.
val run_at : Time.t -> ('z -> 'h) -> 'z -> (_, 'h) t
Let
t = run_at time f z
. Attime
, this runsf z
and transitionsstatus t
toHappened h
, whereh
is result off z
.More precisely, at
time
, providedabort t a
has not previously been called, this will callf z
, with the guarantee thatstatus t = Scheduled_at time
. Iff z
returnsh
and did not callabort t a
, thenstatus t
becomesHappened h
. Iff z
callsabort t a
, then the result off
is ignored, andstatus t
isAborted a
.If
f z
raises, thenstatus t
does not transition and remainsScheduled_at time
, and the exception is sent to the monitor in effect whenrun_at
was called.
val run_after : Time.Span.t -> ('z -> 'h) -> 'z -> (_, 'h) t
module Abort_result = Async_kernel.Time_source.Event.Abort_result
val abort : ('a, 'h) t -> 'a -> ('a, 'h) Abort_result.t
abort t
changesstatus t
toAborted
and returnsOk
, unlesst
previously happened or was previously aborted.
val abort_exn : ('a, 'h) t -> 'a -> unit
abort_exn t a
returnsunit
ifabort t a = `Ok
, and otherwise raises.
val abort_if_possible : ('a, _) t -> 'a -> unit
abort_if_possible t a = ignore (abort t a)
.
module Fired = Async_kernel.Time_source.Event.Fired
val fired : ('a, 'h) t -> ('a, 'h) Fired.t Async_kernel__.Clock_intf.Deferred.t
module Reschedule_result = Async_kernel.Time_source.Event.Reschedule_result
val reschedule_at : ('a, 'h) t -> Time.t -> ('a, 'h) Reschedule_result.t
reschedule_at t
andreschedule_after t
change the time thatt
will fire, if possible, and if not, give a reason why. Likerun_at
, if the requested time is in the past, the event will be scheduled to run immediately. Ifreschedule_at t time = Ok
, then subsequentlyscheduled_at t = time
.
val reschedule_after : ('a, 'h) t -> Time.Span.t -> ('a, 'h) Reschedule_result.t
val at : Time.t -> (_, unit) t
at time
isrun_at time ignore ()
.after time
isrun_after time ignore ()
.You should generally prefer to use the
run_*
functions, which allow you to synchronously update state via a user-supplied function when the event transitions toHappened
. That is, there is an important difference between:let t = run_at time f ()
and:
let t = at time in fired t >>> function | Happened () -> f () | Aborted () -> ()
With
run_at
, ifstatus t = Happened
, one knows thatf
has run. Withat
andfired
, one does not know whetherf
has yet run; it may still be scheduled to run. Thus, withat
andfired
, it is easy to introduce a race. For example, consider these two code snippets:let t = Event.after (sec 2.) in upon (Event.fired t) (function | Aborted () -> () | Happened () -> printf "Timer fired"); upon deferred_event (fun () -> match Event.abort t () with | Ok -> printf "Event occurred" | Previously_aborted () -> assert false | Previously_happened () -> printf "Event occurred after timer fired");
let t = Event.run_after (sec 2.) printf "Timer fired" in upon deferred_event (fun () -> match Event.abort t () with | Ok -> printf "Event occurred" | Previously_aborted () -> assert false | Previously_happened () -> printf "Event occurred after timer fired");
In both snippets, if
Event.abort
returnsOk
, "Timer fired" is never printed. However, the first snippet might print "Event occurred after timer fired" and then "Timer fired". This confused ordering cannot happen withEvent.run_after
.
val after : Time.Span.t -> (_, unit) t