|
32 | 32 |
|
33 | 33 | (def asynctopolis (flow/create-flow asynctopolis/config)) |
34 | 34 |
|
35 | | -(show/flow-svg asynctopolis {:show-chans false |
36 | | - :with-content false}) |
37 | | - |
38 | | -;; Coordinate asynchronous operations using `core.async`. |
39 | | -;; While powerful, these operations can become hard to reason about as they grow in complexity. |
40 | | -;; The `core.async.flow` library is a higher-level abstraction for modeling async processes as a Directed Acyclic Graph (DAG). |
41 | | -;; We can visualize flows [flow-monitor](https://github.com/clojure/core.async.flow-monitor). |
| 35 | +(show/flow-svg asynctopolis nil {:show-chans false |
| 36 | + :with-content false}) |
42 | 37 |
|
43 | 38 | ;; He circled the skyline. |
44 | 39 | ;; He watched the channels breathe. |
|
49 | 44 | ;; each role in the great asynchronous allegiance. |
50 | 45 |
|
51 | 46 |
|
52 | | -;; Let's walk through an exploration of such a flow. |
53 | | - |
54 | | -;; ## What We'll Explore |
55 | | - |
56 | | -;; In this notebook, we'll take a look at: |
| 47 | +;; As he flew lower he saw that processes are connected via channels. |
57 | 48 |
|
58 | | -;; 1. **Basic flow structure**: What does a flow look like under the hood? |
59 | | -;; 2. **Static visualization**: How can we inspect its components? |
60 | | -;; 3. **Dynamic interaction**: How do values move through the flow, and what happens when they do? |
| 49 | +(show/flow-svg asynctopolis nil {:chans-as-ports true |
| 50 | + :with-content false}) |
61 | 51 |
|
62 | | -;; This flow models a small system involving aggregation, notification, and reporting. |
63 | | -;; Internally, it consists of processes connected via channels. |
64 | | -(show/flow-svg asynctopolis {:chans-as-ports true |
65 | | - :with-content false}) |
| 52 | +;; Are channels attached to a process, or are they part of it? |
| 53 | +;; You can choose to visualize them as distinct connectors, |
| 54 | +;; or as embedded roles within each process. |
| 55 | +;; Both perspectives reveal useful insights. |
66 | 56 |
|
67 | | -;; Are channels part of a process or not? |
68 | | -;; You decide |
| 57 | +(show/flow-svg asynctopolis nil {:chans-as-ports false |
| 58 | + :with-content false}) |
69 | 59 |
|
70 | | -(show/flow-svg asynctopolis {:chans-as-ports false |
71 | | - :with-content false}) |
72 | | - |
73 | | -;; Let's dig deeper into the details |
| 60 | +;; Wanting to see more, Icarus swooped even lower to survey the processes. |
74 | 61 |
|
75 | 62 | (show/proc-table asynctopolis) |
76 | 63 |
|
77 | | -;; This table gives us a clear list of components in the flow, including their names |
78 | | -;; and behaviors. |
79 | | - |
80 | | -;; Next, let’s examine how these processes are **connected**. |
| 64 | +;; With a clearer understanding of the processes, |
| 65 | +;; he pondered how these processes are connected. |
81 | 66 |
|
82 | 67 | (show/conn-table asynctopolis) |
83 | 68 |
|
84 | | -;; Now we’re seeing the wiring: who talks to whom, and through what channels. |
| 69 | +;; In doing so he realized there are also 2 global channels, |
| 70 | +;; `report` and `error`: |
85 | 71 |
|
| 72 | +(show/flow-svg asynctopolis nil {:chans-as-ports false |
| 73 | + :with-content false |
| 74 | + :show-global-chans true}) |
86 | 75 |
|
87 | | -;; There are 2 global channels, `report` and `error`: |
| 76 | +;; Any process can put messages on `report` and `error`. |
88 | 77 |
|
89 | | -(show/flow-svg asynctopolis {:chans-as-ports false |
90 | | - :with-content false |
91 | | - :show-global-chans true}) |
| 78 | +;; ## Street Level |
92 | 79 |
|
93 | | -;; Any process can put messages on `report` and `error`, |
94 | | -;; which is why we didn't show them until now. |
95 | | - |
96 | | - |
97 | | -;; ## 3. Running the Flow |
98 | | - |
99 | | -;; Time to bring our flow to life! |
100 | | -;; Calling `start` activates the processes and returns a map of the important channels for interaction. |
| 80 | +;; Reaching street level, he called out `start`! |
| 81 | +;; The flow responded, handing him report and error channels in a map. |
101 | 82 |
|
102 | 83 | (def chs (flow/start asynctopolis)) |
103 | | -(flow/resume asynctopolis) |
104 | | - |
105 | | -;; We can now **inject values** into specific points in the flow. |
106 | | -;; Think of this like poking the system and watching how it reacts. |
107 | | - |
108 | | -;; We send a “poke” signal to the `aggregator` process. |
109 | | - |
110 | | -(show/flow-svg asynctopolis {:chans-as-ports false |
111 | | - :with-content false}) |
112 | | - |
113 | | -(flow/inject asynctopolis [:Tallystrix :poke] [true]) |
114 | | - |
115 | | -(show/flow-svg asynctopolis {:chans-as-ports false |
116 | | - :with-content false}) |
117 | | - |
118 | | -;; We send a stat string that is designed to trigger an alert. |
119 | | - |
120 | | -(flow/inject asynctopolis [:Tallystrix :stat] ["abc1000"]) |
121 | 84 |
|
122 | | -;; We send a notification message into the `notifier`. |
| 85 | +;; But still, nothing stirred. So he yelled `resume`! |
123 | 86 |
|
124 | | -(flow/inject asynctopolis [:Claxxus :in] [:sandwich]) |
125 | | - |
126 | | -;; ## 4. Observing the Results |
127 | | - |
128 | | -;; Our flow includes a `report-chan`, where summaries and reports might be sent. |
| 87 | +(flow/resume asynctopolis) |
129 | 88 |
|
130 | 89 | (def report-chan (:report-chan chs)) |
131 | 90 |
|
132 | | -(flow/ping asynctopolis) |
133 | | - |
134 | 91 | (async/poll! report-chan) |
135 | 92 |
|
136 | | -;; After pinging the system, we check if anything landed in the report channel. |
137 | | - |
138 | | -;; We can also inspect the `error-chan`, where any issues in the flow are reported. |
139 | | - |
140 | | -(def error-chan (:error-chan chs)) |
| 93 | +(flow/inject asynctopolis [:Tallystrix :poke] [true]) |
141 | 94 |
|
142 | | -(async/poll! error-chan) |
| 95 | +(flow/inject asynctopolis [:Tallystrix :stat] ["abc1000"]) |
143 | 96 |
|
| 97 | +(show/flow-svg asynctopolis chs {:chans-as-ports false |
| 98 | + :with-content false}) |
144 | 99 |
|
145 | | -;; If something unexpected occurred (e.g., bad input or failed routing), |
146 | | -;; this is where we’d find it. |
| 100 | +;; Tallystrix takes only numbers, `"abc1000"` was not acceptable. |
147 | 101 |
|
148 | | -(show/flow-svg asynctopolis {:chans-as-ports false |
149 | | - :with-content false}) |
| 102 | +;; ## Conclusion |
150 | 103 |
|
151 | | -(flow/stop asynctopolis) |
| 104 | + (flow/stop asynctopolis) |
152 | 105 | (Thread/sleep 1) |
153 | 106 |
|
154 | | -;; TODO: wait for the report and error !< |
155 | | - |
156 | | - |
157 | | -;; Flows implement the `Datafy` protocol so we can inspect them as data... |
158 | | -;; Good luck with that, there's a lot of it |
159 | | - |
160 | | -(datafy/datafy asynctopolis) |
161 | | - |
162 | | - |
163 | | - |
164 | | -; ## Flow |
165 | | - |
166 | | -; At its core, flow is a library for building concurrent, event-driven systems |
167 | | -; using simple, communication-free functions. |
168 | | -; It lets you wire up processes and connect them through channels, |
169 | | -; while keeping control, error handling, and monitoring centralized and declarative. |
170 | | -; |
171 | | -;You define the structure as a directed graph—processes, |
172 | | -; their inputs and outputs, and how they connect—and the flow system takes care of orchestration. |
173 | | -; Your logic remains focused, while flow handles execution, coordination, and lifecycle concerns. |
174 | | -; |
175 | | -;All processes can be inspected or observed, and flows are fully data-driven, making them easy to reason about and visualize. |
176 | | -; It's concurrent programming with structure—without the chaos. |
177 | | - |
178 | | -; ## Summary |
179 | | - |
180 | | -;; By constructing, inspecting, and interacting with a flow, we can understand the |
181 | | -;; lifecycle and structure of asynchronous systems more clearly. |
182 | | -;; |
183 | | -;; This toolset provides a bridge between the abstract beauty of DAGs and the |
184 | | -;; gritty realism of channel communication—unlocking both power and clarity |
185 | | -;; in asynchronous Clojure code. |
| 107 | +;; Icarus realized that |
| 108 | +;; Flow is a library for building concurrent, event-driven systems |
| 109 | +;; out of simple, communication-free functions. |
| 110 | +;; Processes connect through channels. |
| 111 | +;; You define the structure as a directed graph. |
| 112 | +;; Flow takes care of orchestration. |
| 113 | +;; Flows are data-driven, easy to inspect, reason about and visualize. |
| 114 | +;; Then he wondered just how high could he fly? |
186 | 115 |
|
187 | | -;; Happy flowing! |
| 116 | +;; Happy flowing, and keep your feathers waxed! |
0 commit comments