src/watcher.bend
bend-kube-runtime@0.2.0.0 · 193 lines · 24 definitions
1import Base
2import bend-kube-runtime@0.2.0.0/src/json.bend as J
3import bend-kube-runtime@0.2.0.0/src/core.bend as C
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27type Phase is Data:
28 WList{cont: String}
29 WWatch{rv: String}
30
31
32
33type WState is Data:
34 WState{phase: Phase, fails: U32, first: Bool}
35
36type Input is Data:
37 IPage{page: C.Page}
38 IListErr{code: U32}
39 IEvent{ev: C.WEvent}
40 IWatchEnd{}
41 IWatchErr{code: U32}
42
43
44type Out is Data:
45 OInit{}
46 OInitApply{obj: J.Json}
47 OInitDone{}
48 OApply{obj: J.Json}
49 ODelete{obj: J.Json}
50
51
52
53type Step is Data:
54 Step{state: WState, outs: List<&2, Out>, wait: Bool}
55
56def WState.init() -> WState:
57 WState{WList{""}, 0, True{}}
58
59def Backoff.delay.go(+fails: U32, capped: Bool) -> U32:
60 match capped:
61 case True{}:
62 30000
63 case False{}:
64 U32.min((800 << U32.to_nat((fails - 1 : U32)) : U32), 30000)
65
66
67
68
69
70
71def Backoff.delay(+fails: U32) -> U32:
72 Backoff.delay.go(fails, U32.is_ge(fails, 6))
73
74
75
76
77def Watcher.page_outs(xs: List<&2, J.Json>, tail: List<&2, Out>) -> List<&2, Out>:
78 match xs:
79 case Nil{}:
80 tail
81 case Con{x, t}:
82 OInitApply{x} <> Watcher.page_outs(t, tail)
83
84def Watcher.init_out(first: Bool, rest: List<&2, Out>) -> List<&2, Out>:
85 match first:
86 case True{}:
87 OInit{} <> rest
88 case False{}:
89 rest
90
91def Watcher.done_out(last: Bool) -> List<&2, Out>:
92 match last:
93 case True{}:
94 [OInitDone{}]
95 case False{}:
96 Nil{}
97
98def Watcher.page_phase(rv: String, +cont: String, last: Bool) -> Phase:
99 match last:
100 case True{}:
101 WWatch{rv}
102 case False{}:
103 WList{cont}
104
105def Watcher.page.go(first: Bool, items: List<&2, J.Json>, rv: String, +cont: String,
106 +last: Bool) -> Step:
107 Step{WState{Watcher.page_phase(rv, cont, last), 0, last},
108 Watcher.init_out(first, Watcher.page_outs(items, Watcher.done_out(last))), False{}}
109
110
111
112def Watcher.page(first: Bool, p: C.Page) -> Step:
113 match p:
114 case C.Page{items, rv, +cont}:
115 Watcher.page.go(first, items, rv, cont, String.is_empty(cont))
116
117def Watcher.is_gone(+code: U32) -> Bool:
118 U32.is_eq(code, 410)
119
120def Watcher.relist(+fails: U32) -> Step:
121 Step{WState{WList{""}, fails, True{}}, Nil{}, False{}}
122
123def Watcher.retry(p: Phase, +fails: U32, first: Bool) -> Step:
124 Step{WState{p, (fails + 1 : U32), first}, Nil{}, True{}}
125
126
127
128def Watcher.list_err(cont: String, +fails: U32, first: Bool, gone: Bool) -> Step:
129 match gone:
130 case True{}:
131 Watcher.relist(fails)
132 case False{}:
133 Watcher.retry(WList{cont}, fails, first)
134
135def Watcher.watch_err(rv: String, +fails: U32, gone: Bool) -> Step:
136 match gone:
137 case True{}:
138 Watcher.relist(fails)
139 case False{}:
140 Watcher.retry(WWatch{rv}, fails, False{})
141
142
143def Watcher.event(rv: String, +fails: U32, ev: C.WEvent) -> Step:
144 match ev:
145 case C.WAdded{+o}:
146 Step{WState{WWatch{C.Obj.rv(o)}, 0, False{}}, [OApply{o}], False{}}
147 case C.WModified{+o}:
148 Step{WState{WWatch{C.Obj.rv(o)}, 0, False{}}, [OApply{o}], False{}}
149 case C.WDeleted{+o}:
150 Step{WState{WWatch{C.Obj.rv(o)}, 0, False{}}, [ODelete{o}], False{}}
151 case C.WBookmark{v}:
152 Step{WState{WWatch{v}, 0, False{}}, Nil{}, False{}}
153 case C.WError{C.Status{+code, r, m}}:
154 Watcher.watch_err(rv, fails, Watcher.is_gone(code))
155 case C.WBad{m}:
156 Watcher.retry(WWatch{rv}, fails, False{})
157
158
159def Watcher.step(st: WState, i: Input) -> Step:
160 match st i:
161 case WState{WList{c}, f, first} IPage{p}:
162 Watcher.page(first, p)
163 case WState{WList{c}, +f, first} IListErr{+code}:
164 Watcher.list_err(c, f, first, Watcher.is_gone(code))
165 case WState{WWatch{rv}, +f, first} IEvent{ev}:
166 Watcher.event(rv, f, ev)
167 case WState{WWatch{rv}, f, first} IWatchEnd{}:
168 Step{WState{WWatch{rv}, 0, False{}}, Nil{}, False{}}
169 case WState{WWatch{rv}, +f, first} IWatchErr{+code}:
170 Watcher.watch_err(rv, f, Watcher.is_gone(code))
171 case s _:
172
173 Step{s, Nil{}, False{}}
174
175def Watcher.merge.go(outs: List<&2, Out>, w: Bool, s: Step) -> Step:
176 match s:
177 case Step{st, more, w2}:
178 Step{st, List.append(&2, Out, outs, more), Bool.or(w, w2)}
179
180
181
182
183def Watcher.merge(acc: Step, x: Input) -> Step:
184 match acc:
185 case Step{st, outs, w}:
186 Watcher.merge.go(outs, w, Watcher.step(st, x))
187
188def Watcher.steps(xs: List<&2, Input>, acc: Step) -> Step:
189 match xs:
190 case Nil{}:
191 acc
192 case Con{x, t}:
193 Watcher.steps(t, Watcher.merge(acc, x))