Source file core_lifecycle.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
let log_src = Logs.Src.create "sihl.core.container"
let () = Printexc.record_backtrace true
module Logs = (val Logs.src_log log_src : Logs.LOG)
exception Exception
type lifecycle =
{ type_name : string
; implementation_name : string
; id : int
; dependencies : unit -> lifecycle list
; start : unit -> unit Lwt.t
; stop : unit -> unit Lwt.t
}
let counter = ref 0
let create_lifecycle
?(dependencies = fun () -> [])
?(start = fun () -> Lwt.return ())
?(stop = fun () -> Lwt.return ())
?implementation_name
type_name
=
counter := !counter + 1;
let implementation_name =
Option.value implementation_name ~default:type_name
in
{ type_name; implementation_name; id = !counter; dependencies; start; stop }
;;
let human_name lifecycle =
Format.asprintf "%s %s" lifecycle.type_name lifecycle.implementation_name
;;
module Map = Map.Make (Int)
let collect_all_lifecycles lifecycles =
let rec collect_lifecycles lifecycle =
match lifecycle.dependencies () with
| [] -> [ lifecycle ]
| lifecycles ->
List.cons
lifecycle
(lifecycles
|> List.map (fun lifecycle -> collect_lifecycles lifecycle)
|> List.concat)
in
lifecycles
|> List.map collect_lifecycles
|> List.concat
|> List.map (fun lifecycle -> lifecycle.id, lifecycle)
|> List.to_seq
|> Map.of_seq
;;
let top_sort_lifecycles lifecycles =
let lifecycles = collect_all_lifecycles lifecycles in
let lifecycle_graph =
lifecycles
|> Map.to_seq
|> List.of_seq
|> List.map (fun (id, lifecycle) ->
let dependencies =
lifecycle.dependencies () |> List.map (fun dep -> dep.id)
in
id, dependencies)
in
match Tsort.sort lifecycle_graph with
| Tsort.Sorted sorted ->
sorted
|> List.map (fun id ->
match Map.find_opt id lifecycles with
| Some l -> l
| None ->
Logs.err (fun m -> m "Failed to sort lifecycles.");
raise Exception)
| Tsort.ErrorCycle remaining_ids ->
let remaining_names =
List.map
(fun id -> lifecycles |> Map.find_opt id |> Option.map human_name)
remaining_ids
|> CCList.all_some
in
let msg = "Cycle detected while starting lifecycles." in
let remaining_msg =
Option.map
(fun r ->
Format.asprintf
"%s These are the lifecycles after the cycle: %s"
msg
(String.concat ", " r))
remaining_names
in
Logs.err (fun m -> m "%s" @@ Option.value remaining_msg ~default:msg);
raise Exception
;;