-
Notifications
You must be signed in to change notification settings - Fork 0
/
system.clj
57 lines (50 loc) · 1.86 KB
/
system.clj
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
(ns init.system
(:require [init.component :as component]
[init.graph :as graph]
[init.errors :as errors]))
;; TODO: Add hooks to report starting/stopping components, e.g. for logging
(defn- stop-component [component value exception]
(try
(component/stop component value)
exception
(catch Exception e
(let [wrapped (errors/stop-failed-exception component value e)]
(if exception
(doto ^Throwable exception (.addSuppressed wrapped))
wrapped)))))
(defn- stop-system
([system graph selectors]
(stop-system system graph selectors nil))
([system graph selectors exception]
(reduce (fn [ex [k c]]
(stop-component c (system k) ex))
exception
(graph/reverse-dependency-order graph selectors))))
(defn- start-component
[system graph name component]
(let [inputs (->> (graph/required-keys graph name)
(map (partial map system)))]
(try
(assoc system name (component/start component inputs))
(catch Exception ex
(->> (errors/start-failed-exception component ex)
(stop-system system graph (keys system))
throw)))))
;; We could keep an atom of the current system and support a special
;; component protocol for system-aware components. Those could receive
;; the atom or a readonly view on it, and can then dereference the
;; system at any time, allowing runtime inspection.
(defn start
"Starts a system from a dependency graph."
[graph selectors]
(-> (reduce (fn [system [k c]]
(start-component system graph k c))
{}
(graph/dependency-order graph selectors))
(with-meta {::graph graph})))
(defn stop
"Stops a system map."
[system selectors]
(let [graph (-> system meta ::graph)]
(when-let [ex (stop-system system graph selectors)]
(throw ex))))