Merge pull request #100 from shonfeder/fix-non-atomic-metric-callbacks

fix: make metric callbacks atomic
This commit is contained in:
Simon Cruanes 2025-09-02 15:15:16 -04:00 committed by GitHub
commit ecd6ed0b73
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1071,7 +1071,8 @@ end = struct
[ [
"exception.message", `String (Printexc.to_string exn); "exception.message", `String (Printexc.to_string exn);
"exception.type", `String (Printexc.exn_slot_name exn); "exception.type", `String (Printexc.exn_slot_name exn);
"exception.stacktrace", `String (Printexc.raw_backtrace_to_string bt); ( "exception.stacktrace",
`String (Printexc.raw_backtrace_to_string bt) );
] ]
in in
scope.items <- Ev (ev, scope.items) scope.items <- Ev (ev, scope.items)
@ -1454,7 +1455,12 @@ end
alarms/intervals to emit them. *) alarms/intervals to emit them. *)
module Metrics_callbacks = struct module Metrics_callbacks = struct
open struct open struct
let cbs_ : (unit -> Metrics.t list) list ref = ref [] (* [true] iff the initial list of metric callbacks has already been registered
with `on_tick`. This registration must only happen once, after which,
[registered_with_on_tick] will forever be [false]. *)
let registered_with_on_tick : bool Atomic.t = Atomic.make false
let cbs_ : (unit -> Metrics.t list) AList.t = AList.make ()
end end
(** [register f] adds the callback [f] to the list. (** [register f] adds the callback [f] to the list.
@ -1463,12 +1469,14 @@ module Metrics_callbacks = struct
of metrics. It might be called regularly by the backend, in particular of metrics. It might be called regularly by the backend, in particular
(but not only) when {!Collector.tick} is called. *) (but not only) when {!Collector.tick} is called. *)
let register f : unit = let register f : unit =
if !cbs_ = [] then (* sets [registered_with_on_tick] to [true] atomically, iff it is currently
[false]. *)
if not (Atomic.exchange registered_with_on_tick true) then
(* make sure we call [f] (and others) at each tick *) (* make sure we call [f] (and others) at each tick *)
Collector.on_tick (fun () -> Collector.on_tick (fun () ->
let m = List.map (fun f -> f ()) !cbs_ |> List.flatten in let m = List.map (fun f -> f ()) (AList.get cbs_) |> List.flatten in
Metrics.emit m); Metrics.emit m);
cbs_ := f :: !cbs_ AList.add cbs_ f
end end
(** {2 Logs} *) (** {2 Logs} *)