Skip to content

Commit 93681ce

Browse files
add some narrative to the stats examples
1 parent fb33a5a commit 93681ce

File tree

2 files changed

+89
-17
lines changed

2 files changed

+89
-17
lines changed

notebooks/core/async/flow/example/stats.clj

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,18 @@
66
:category :clojure
77
:tags [:core.async :core.async.flow]}}}
88
(ns core.async.flow.example.stats
9-
(:require
10-
[clojure.core.async :as a]
11-
[clojure.core.async.flow :as flow]
12-
[clojure.core.async.flow-monitor :as mon]))
9+
(:require [clojure.core.async :as a]
10+
[clojure.core.async.flow :as flow]
11+
[clojure.core.async.flow-monitor :as mon]))
1312

14-
;; # Core async flow stats example
15-
;;
16-
;; Adapted from https://github.com/puredanger/flow-example
13+
;; Recently Alex provided a video walkthrough on how to use `core.async.flow` to build a stats monitor.
1714

18-
^:kind/video
15+
^:kind/video ^:kindly/hide-code
1916
{:youtube-id "lXFwf3O4BVY"
2017
:iframe-width "100%"}
2118

19+
;; This notebook is adapted from [his code](https://github.com/puredanger/flow-example).
20+
2221
(defn stat-gen
2322
"Generates a random value between min (inclusive) and max (exclusive)
2423
and writes it to out chan, waiting wait ms between until stop-atom is flagged."

notebooks/core/async/flow/exploration.clj

Lines changed: 82 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,40 +12,113 @@
1212
[core.async.flow.example.stats :as stats]
1313
[core.async.flow.visualization :as fv]))
1414

15-
;; # Visualizing core.async.flows
15+
;; One of Clojure’s superpowers is the ability to coordinate asynchronous operations
16+
;; using `core.async`.
17+
;; While powerful, these operations can become hard to reason about as they grow in complexity.
1618

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

2126
;; ## What We'll Explore
2227

23-
;; 1. Basic flow structure (processes, channels, connections)
24-
;; 2. Static visualization of a sample flow
25-
;; 3. Evolution as the flow changes
28+
;; In this notebook, we'll take a look at:
29+
30+
;; 1. **Basic flow structure**: What does a flow look like under the hood?
31+
;; 2. **Static visualization**: How can we inspect its components?
32+
;; 3. **Dynamic interaction**: How do values move through the flow, and what happens when they do?
33+
34+
;; ## 1. Creating a Flow
35+
36+
;; Flows are created from configuration
2637

2738
(def stats-flow
2839
(flow/create-flow stats/config))
2940

41+
;; This flow models a small system involving aggregation, notification, and reporting.
42+
;; Internally, it consists of processes connected via channels.
43+
44+
;; ## 2. Inspecting the Flow
45+
46+
;; Flows implement the `Datafy` protocol so we can inspect them as data.
47+
48+
(datafy/datafy stats-flow)
49+
50+
;; That's a lot to take in! Fortunately, we can make things more digestible
51+
;; by viewing just the **processes** involved.
52+
3053
(fv/proc-table stats-flow)
3154

55+
;; This table gives us a clear list of components in the flow, including their names
56+
;; and behaviors.
57+
58+
;; Next, let’s examine how these processes are **connected**.
59+
3260
(fv/conn-table stats-flow)
3361

62+
;; Now we’re seeing the wiring: who talks to whom, and through what channels.
63+
64+
;; ## 3. Running the Flow
65+
66+
;; Time to bring our flow to life!
67+
;; Calling `start` activates the processes and returns a map of the important channels for interaction.
68+
3469
(def chs (flow/start stats-flow))
3570

71+
;; We can now **inject values** into specific points in the flow.
72+
;; Think of this like poking the system and watching how it reacts.
73+
74+
;; We send a “poke” signal to the `aggregator` process.
75+
3676
@(flow/inject stats-flow [:aggregator :poke] [true])
37-
@(flow/inject stats-flow [:aggregator :stat] ["abc1000"]) ;; trigger an alert
77+
78+
;; We send a stat string that is designed to trigger an alert.
79+
80+
@(flow/inject stats-flow [:aggregator :stat] ["abc1000"])
81+
82+
;; We send a notification message into the `notifier`.
83+
3884
@(flow/inject stats-flow [:notifier :in] [:sandwich])
3985

86+
;; ## 4. Observing the Results
87+
88+
;; Our flow includes a `report-chan`, where summaries and reports might be sent.
89+
4090
(def report-chan (:report-chan chs))
91+
4192
(flow/ping stats-flow)
93+
4294
(async/poll! report-chan)
95+
96+
;; After pinging the system, we check if anything landed in the report channel.
97+
98+
;; We can also inspect the `error-chan`, where any issues in the flow are reported.
99+
43100
(def error-chan (:error-chan chs))
101+
44102
(async/poll! error-chan)
45103

104+
;; If something unexpected occurred (e.g., bad input or failed routing),
105+
;; this is where we’d find it.
106+
;;
107+
;;
108+
;;
46109
;;(flow/stop stats-flow)
47110
;;(async/close! stat-chan)
48111

49112
;; @(flow/inject stats-flow [:aggregator :poke] [true])
50113

51-
(datafy/datafy stats-flow)
114+
115+
; ## Summary
116+
117+
;; By constructing, inspecting, and interacting with a flow, we can understand the
118+
;; lifecycle and structure of asynchronous systems more clearly.
119+
;;
120+
;; This toolset provides a bridge between the abstract beauty of DAGs and the
121+
;; gritty realism of channel communication—unlocking both power and clarity
122+
;; in asynchronous Clojure code.
123+
124+
;; Happy flowing!

0 commit comments

Comments
 (0)