Skip to content

Commit f0b0237

Browse files
update elk layout with structural merge
1 parent ed18b0e commit f0b0237

9 files changed

Lines changed: 373 additions & 205 deletions

File tree

src/clojure+/print/objects_and_protocols.clj

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
[clojure.core.async.flow :as flow]
88
[clojure.datafy :as datafy]
99
[clojure.string :as str]
10-
[core.async.flow.example.stats :as stats]))
10+
[core.async.flow.example.asynctopolis :as asynctopolis]))
1111

1212
;; The Clojure default for printing objects is noisy.
1313
;; Clojure's `print-method` for `Object` delegates to `clojure.core/print-object`
@@ -48,7 +48,7 @@
4848
;; Especially in the world of notebooks where we like to show things as we go,
4949
;; but also just keeping a tidy REPL or looking into data that contains objects.
5050

51-
(flow/create-flow stats/config)
51+
asynctopolis/flow
5252

5353
;; Hmmmm. not so nice. We'll dig into this further below.
5454
;; But we also need to be aware that Clojure munges it's names to make Java valid names.
@@ -112,7 +112,7 @@
112112

113113
*ns*
114114
(((fn aaa [] (fn bbb [] (fn ccc [])))))
115-
(flow/create-flow stats/config)
115+
asynctopolis/flow
116116

117117
;; What is this? It's a reified object that implements protocols.
118118
;; We can see this by the $reify part at the end.
@@ -135,10 +135,7 @@
135135
;; On the other hand, at my REPL I don't care about that, it's faster than I can notice.
136136
;; Leaving aside those concerns, it returns quite a long list...
137137

138-
(def stats-flow
139-
(flow/create-flow stats/config))
140-
141-
(all-protocol-vars stats-flow)
138+
(all-protocol-vars asynctopolis/flow)
142139

143140
;; But notice that one of them; `#'clojure.core.async.flow.impl.graph/Graph`
144141
;; just feels like it is the one we care about most.
@@ -155,7 +152,7 @@
155152
(defn protocol-ns-matches [x]
156153
(filter #(ns-match? % x) (all-protocol-vars x)))
157154

158-
(protocol-ns-matches stats-flow)
155+
(protocol-ns-matches asynctopolis/flow)
159156

160157
;; Nice.
161158
;; In my opinion this is more representative of the object.
@@ -169,20 +166,20 @@
169166
(->> (protocol-ns-matches x)
170167
(map var-sym)))
171168

172-
(protocol-ns-match-names stats-flow)
169+
(protocol-ns-match-names asynctopolis/flow)
173170

174171
;; The other protocol of interest is Datafiable,
175172
;; because it indicates I can get a data representation if I would like to.
176173

177-
(datafy/datafy stats-flow)
174+
(datafy/datafy asynctopolis/flow)
178175

179176
;; I think this one is so helpful that it should always be shown on objects,
180177
;; regardless of their type of other protocols,
181178
;; as a hint that it is possible to get more information.
182179
;; I wouldn't want to print them as data by default, because it would be too spammy.
183180
;; And checking Datafiable is much less of a performance concern.
184181

185-
(satisfies? clojure.core.protocols/Datafiable stats-flow)
182+
(satisfies? clojure.core.protocols/Datafiable asynctopolis/flow)
186183

187184
;; But there is a big problem... **everything** is Datafiable...
188185

src/core/async/flow/example/stats.clj renamed to src/core/async/flow/example/asynctopolis.clj

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@
22
:clay {:title "Stats and Signals in the Flow of Asynctopolis"
33
:quarto {:author [:alexmiller :timothypratley]
44
:type :post
5+
:draft true
56
:date "2025-05-1"
67
:category :clojure
78
:tags [:core.async :core.async.flow]}}}
8-
(ns core.async.flow.example.stats
9+
(ns core.async.flow.example.asynctopolis
910
(:require [clojure.core.async :as a]
1011
[clojure.core.async.flow :as flow]
1112
[clojure.core.async.flow-static :as flow-static]
@@ -311,18 +312,18 @@
311312
;; Held together by channels, purpose, and trust.
312313

313314
(def config
314-
{:procs {:generator {:args {:min 0 :max 12 :wait 500}
315+
{:procs {:Randomius {:args {:min 0 :max 12 :wait 500}
315316
:proc (flow/process #'Randomius)}
316-
:aggregator {:args {:min 1 :max 10}
317+
:Tallystrix {:args {:min 1 :max 10}
317318
:proc (flow/process #'Tallystrix)}
318-
:scheduler {:args {:wait 3000}
319+
:Chronon {:args {:wait 3000}
319320
:proc (flow/process #'Chronon)}
320-
:notifier {:args {:prefix "Alert: "}
321+
:Claxxus {:args {:prefix "Alert: "}
321322
:proc (flow/process #'Claxxus)
322323
:chan-opts {:in {:buf-or-n (a/sliding-buffer 3)}}}}
323-
:conns [[[:generator :out] [:aggregator :stat]]
324-
[[:scheduler :out] [:aggregator :poke]]
325-
[[:aggregator :alert] [:notifier :in]]]})
324+
:conns [[[:Randomius :out] [:Tallystrix :stat]]
325+
[[:Chronon :out] [:Tallystrix :poke]]
326+
[[:Tallystrix :alert] [:Claxxus :in]]]})
326327

327328
^:kind/hiccup
328329
[:iframe {:width "100%"
@@ -333,13 +334,13 @@
333334
;; Describe your duties.
334335
;; Initialize your station.
335336

336-
(def f (flow/create-flow config))
337+
(def flow (flow/create-flow config))
337338

338339
;; The city is ready, but not yet in action.
339340

340-
(datafy/datafy f)
341+
(datafy/datafy flow)
341342

342-
(def chs (flow/start f))
343+
(def chs (flow/start flow))
343344

344345
chs
345346

@@ -354,22 +355,22 @@ chs
354355
;; The city breathes, the asynchronous allegiance stirs.
355356
;; Transition with order.
356357

357-
(flow/resume f)
358+
(flow/resume flow)
358359

359360
;; Transform with purpose.
360361

361-
(flow/inject f [:aggregator :poke] [true])
362-
(flow/inject f [:aggregator :stat] ["abc1000"]) ;; trigger an alert
363-
(flow/inject f [:notifier :in] [:sandwich])
362+
(flow/inject flow [:Tallystrix :poke] [true])
363+
(flow/inject flow [:Tallystrix :stat] ["abc1000"]) ;; trigger an alert
364+
(flow/inject flow [:Claxxus :in] [:sandwich])
364365

365366
(a/poll! (:report-chan chs))
366367
(a/poll! (:error-chan chs))
367368

368369
;; The flow can coordinate peace.
369370

370-
(flow/pause f)
371+
(flow/pause flow)
371372

372-
(flow/stop f)
373+
(flow/stop flow)
373374

374375
;; The city falls silent.
375376

src/core/async/flow/exploration.clj renamed to src/core/async/flow/example/before_his_wings_melted.clj

Lines changed: 49 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,52 @@
11
^{:kindly/hide-code true
2-
:clay {:title "Core Async Flow Exploration"
2+
:clay {:title "What He Saw Before His Wings Melted"
33
:quarto {:author [:daslu :timothypratley]
44
:type :post
55
:draft true
66
:date "2025-05-1"
77
:category :clojure
88
:tags [:core.async :core.async.flow]}}}
9-
(ns core.async.flow.exploration
9+
(ns core.async.flow.example.before-his-wings-melted
1010
(:require [clojure.core.async :as async]
1111
[clojure.core.async.flow :as flow]
1212
[clojure.datafy :as datafy]
13-
[core.async.flow.example.stats :as stats]
14-
[core.async.flow.visualization :as fv]))
13+
[core.async.flow.example.asynctopolis :as asynctopolis]
14+
[core.async.flow.example.flow-show :as show]))
1515

16-
;; One of Clojure’s superpowers is the ability to coordinate asynchronous operations
17-
;; using `core.async`.
16+
;; Long before he flew too high,
17+
;; before the wax gave way and the world remembered only his fall,
18+
;; Iccarus flew *low*.
19+
;; They often leave out this part of his misadventures,
20+
;; when curiosity, not hubris, guided his wings.
21+
;; He flew not to ascend to Olympus,
22+
;; but rather to get a good view of the lesser known Asynctopolis.
23+
24+
;; A city pulsing with signals, stitched together by invisible threads.
25+
;; From above, its patterns unfolded like a diagram.
26+
;; Flows of information, agents in silent collaboration,
27+
;; each unaware of the others, yet perfectly aligned.
28+
29+
;; This is what he saw.
30+
31+
;; ## Asynctopolis from the Clouds
32+
33+
(show/flow-svg asynctopolis/flow {:show-chans false
34+
:with-content false})
35+
36+
;; Coordinate asynchronous operations using `core.async`.
1837
;; While powerful, these operations can become hard to reason about as they grow in complexity.
38+
;; The `core.async.flow` library is a higher-level abstraction for modeling async processes as a Directed Acyclic Graph (DAG).
39+
;; We can visualize flows [flow-monitor](https://github.com/clojure/core.async.flow-monitor).
40+
41+
;; He circled the skyline.
42+
;; He watched the channels breathe.
43+
;; And slowly, he spiraled down,
44+
;; drawn not by ambition, but fascination—
45+
;; closer to each process,
46+
;; each transformation,
47+
;; each role in the great asynchronous allegiance.
48+
1949

20-
;; The new `core.async.flow` library offers a higher-level abstraction for modeling
21-
;; async processes as a **Directed Acyclic Graph (DAG)**.
22-
;; And now, with [flow-monitor](https://github.com/clojure/core.async.flow-monitor),
23-
;; we can *visualize* and *analyze* those flows.
24-
;;
2550
;; Let's walk through an exploration of such a flow.
2651

2752
;; ## What We'll Explore
@@ -32,78 +57,68 @@
3257
;; 2. **Static visualization**: How can we inspect its components?
3358
;; 3. **Dynamic interaction**: How do values move through the flow, and what happens when they do?
3459

35-
;; ## 1. Creating a Flow
36-
37-
;; Flows are created from configuration
38-
39-
(def stats-flow
40-
(flow/create-flow stats/config))
41-
42-
(fv/flow-svg stats-flow)
43-
4460
;; This flow models a small system involving aggregation, notification, and reporting.
4561
;; Internally, it consists of processes connected via channels.
62+
(show/flow-svg asynctopolis/flow {:chans-as-ports true
63+
:with-content false})
4664

47-
;; ## 2. Inspecting the Flow
65+
(show/flow-svg asynctopolis/flow {:chans-as-ports false
66+
:with-content false})
4867

49-
;; That's a lot to take in! Fortunately, we can make things more digestible
50-
;; by viewing just the **processes** involved.
5168

52-
(fv/proc-table stats-flow)
69+
(show/proc-table asynctopolis/flow)
5370

5471
;; This table gives us a clear list of components in the flow, including their names
5572
;; and behaviors.
5673

5774
;; Next, let’s examine how these processes are **connected**.
5875

59-
(fv/conn-table stats-flow)
76+
(show/conn-table asynctopolis/flow)
6077

6178
;; Now we’re seeing the wiring: who talks to whom, and through what channels.
6279

6380
;; Flows implement the `Datafy` protocol so we can inspect them as data...
6481
;; Good luck with that, there's a lot of it
6582

6683
^:kind/portal
67-
(datafy/datafy stats-flow)
84+
(datafy/datafy asynctopolis/flow)
6885

6986

7087
;; ## 3. Running the Flow
7188

7289
;; Time to bring our flow to life!
7390
;; Calling `start` activates the processes and returns a map of the important channels for interaction.
7491

75-
(def chs (flow/start stats-flow))
76-
7792
;; We can now **inject values** into specific points in the flow.
7893
;; Think of this like poking the system and watching how it reacts.
7994

8095
;; We send a “poke” signal to the `aggregator` process.
8196

82-
@(flow/inject stats-flow [:aggregator :poke] [true])
97+
@(flow/inject asynctopolis/flow [:Tallystrix :poke] [true])
8398

8499
;; We send a stat string that is designed to trigger an alert.
85100

86-
@(flow/inject stats-flow [:aggregator :stat] ["abc1000"])
101+
@(flow/inject asynctopolis/flow [:Tallystrix :stat] ["abc1000"])
87102

88103
;; We send a notification message into the `notifier`.
89104

90-
@(flow/inject stats-flow [:notifier :in] [:sandwich])
105+
@(flow/inject asynctopolis/flow [:Claxxus :in] [:sandwich])
91106

92107
;; ## 4. Observing the Results
93108

94109
;; Our flow includes a `report-chan`, where summaries and reports might be sent.
95110

96-
(def report-chan (:report-chan chs))
111+
(def report-chan (:report-chan asynctopolis/chs))
97112

98-
(flow/ping stats-flow)
113+
(flow/ping asynctopolis/flow)
99114

100115
(async/poll! report-chan)
101116

102117
;; After pinging the system, we check if anything landed in the report channel.
103118

104119
;; We can also inspect the `error-chan`, where any issues in the flow are reported.
105120

106-
(def error-chan (:error-chan chs))
121+
(def error-chan (:error-chan asynctopolis/chs))
107122

108123
(async/poll! error-chan)
109124

0 commit comments

Comments
 (0)