-
Notifications
You must be signed in to change notification settings - Fork 0
/
system.cljc
118 lines (98 loc) · 3.91 KB
/
system.cljc
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
(ns slip.system
"a container for a stateful system of objects,
and the specification for the system.
both the system and the specification can be updated.
the system is lazily created, but is safe for access and
update in multi-threaded scenarios"
(:require
[promesa.core :as p]
[taoensso.timbre :refer [error]]
[slip.protocols :as pt]
[slip.system-map :as system-map]))
(defrecord SlipSystem [label system-spec-a system-map-p-container]
pt/ISlipSystem
(-spec [_] @system-spec-a)
(-reset-spec! [_ system-spec]
(reset! system-spec-a system-spec))
(-system-map [_]
@system-map-p-container)
(-start! [_ opts resolve-fn reject-fn]
(#?(:clj send :cljs swap!)
system-map-p-container
(fn [system-map-p]
(let [started-system-map-p (p/then
system-map-p
#(system-map/start! % opts))]
;; return a result to the caller
(p/handle
started-system-map-p
(fn [succ err]
(if (some? err)
(reject-fn err)
(resolve-fn
(system-map/dissoc-impl-keys succ)))))
;; update the container value
started-system-map-p))))
(-stop! [_ opts resolve-fn reject-fn]
(#?(:clj send :cljs swap!)
system-map-p-container
(fn [system-map-p]
(let [stopped-system-map-p (p/then
system-map-p
#(system-map/stop! % opts))
;; if the system stopped cleanly, then
;; reinitialise it with the potentially updated spec.
;; if there was an error, keep it - reinit! will be
;; required
maybe-new-system-map-p (p/handle
stopped-system-map-p
(fn [_succ err]
(if (some? err)
(p/rejected err)
(system-map/init @system-spec-a))))]
;; then return the result of stop! to the caller
(p/handle
stopped-system-map-p
(fn [succ err]
(if (some? err)
(reject-fn err)
(resolve-fn
(system-map/dissoc-impl-keys succ)))))
;; update the container value
maybe-new-system-map-p))))
(-reinit! [_ resolve-fn reject-fn]
(#?(:clj send :cljs swap!)
system-map-p-container
(fn [system-map-p]
(let [next-system-map-p (-> system-map-p
(p/handle
;; first stop the system if running
(fn [succ err]
(if (some? err)
(p/rejected err)
(system-map/stop! succ))))
;; catch any errors and ignore before reinit
(p/handle
(fn [_system-map err]
(when (some? err)
(error err "ignoring previous error"))
(system-map/init @system-spec-a))))]
;; return result to the caller
(p/handle
next-system-map-p
(fn [succ err]
(if (some? err)
(reject-fn err)
(resolve-fn
(system-map/dissoc-impl-keys succ)))))
;; update the container value
next-system-map-p)))))
;; use an agent container on clj to serialize system actions
(defn slip-system
[label system-spec]
(map->SlipSystem
{:label (str label)
:system-spec-a (atom system-spec)
:system-map-p-container
#?(:clj (agent (p/resolved (system-map/init system-spec)))
:cljs (atom (p/resolved (system-map/init system-spec))))}))