What He Saw Before His Wings Melted
Long before he flew too high, before the wax gave way and the world remembered only his fall, Icarus flew low. They often leave out this part of his misadventures, when curiosity, not hubris, guided his wings. He flew not to ascend to Olympus, but rather to get a good view of the lesser known Asynctopolis.
A city pulsing with signals, stitched together by invisible threads. From above, its patterns unfolded like a diagram. Flows of information, agents in silent collaboration, each unaware of the others, yet perfectly aligned.
This is what he saw.
Asynctopolis from the Clouds
(def asynctopolis (flow/create-flow asynctopolis/config))(show/flow-svg asynctopolis nil {:show-chans false
:with-content false})He circled the skyline. He watched the channels breathe. And slowly, he spiraled down, drawn not by ambition, but fascination— closer to each process, each transformation, each role in the great asynchronous allegiance.
As he flew lower he saw that processes are connected via channels.
(show/flow-svg asynctopolis nil {:chans-as-ports true
:with-content false})Are channels attached to a process, or are they part of it? You can choose to visualize them as distinct connectors, or as embedded roles within each process. Both perspectives reveal useful insights.
(show/flow-svg asynctopolis nil {:chans-as-ports false
:with-content false})Wanting to see more, Icarus swooped even lower to survey the processes.
(show/proc-table asynctopolis)| process | start params | in chans | out chans |
|---|---|---|---|
| Tallystrix |
min: 1
Min value, alert if lower
max: 10
Max value, alert if higher
|
stat: Channel to receive stat values
poke: Channel to poke when it is time to report a window of data to the log
|
alert: Notify of value out of range {:val value, :error :high|:low
|
| Chronon |
wait: 3000
Time to wait between pokes
|
out: Poke channel, will send true when the alarm goes off
|
|
| Claxxus |
prefix: Alert:
Log message prefix
|
in: Channel to receive messages
|
|
| Randomius |
min: 0
Min value to generate
max: 12
Max value to generate
wait: 500
Time in ms to wait between generating
|
out: Output channel for stats
|
With a clearer understanding of the processes, he pondered how these processes are connected.
(show/conn-table asynctopolis)| source | target |
|---|---|
| Randomius_out | Tallystrix_stat |
| Chronon_out | Tallystrix_poke |
| Tallystrix_alert | Claxxus_in |
In doing so he realized there are also 2 global channels, report and error:
(show/flow-svg asynctopolis nil {:chans-as-ports false
:with-content false
:show-global-chans true})Any process can put messages on report and error.
Street Level
Reaching street level, he called out start! The flow responded, handing him report and error channels in a map.
(def chs (flow/start asynctopolis))Randomius initialing
Tallystrix initializing
Chronon initializing
Claxxus initializing
But still, nothing stirred. So he yelled resume!
(flow/resume asynctopolis)true(def report-chan (:report-chan chs))(async/poll! report-chan)nil(flow/inject asynctopolis [:Tallystrix :poke] [true])#object [FutureTask](flow/inject asynctopolis [:Tallystrix :stat] ["abc1000"])Randomius transitioning :clojure.core.async.flow/resume
Talon, set flight!
SQUARK: 11
Chronon transitioning :clojure.core.async.flow/resume
Chronon running
Chronon transforms :alarm true to :out
Tallystrix transitioning :clojure.core.async.flow/resume
#object [FutureTask](show/flow-svg asynctopolis chs {:chans-as-ports false
:with-content false})Claxxus transitioning :clojure.core.async.flow/resume
Tallystrix transforming :poke true
Tallystrix transforming :stat abc1000
Tallystrix transforming :poke true
Randomius transform 11 from :stat to :out
Tallystrix transforming :stat 11
Claxxus transforming :in {:val 11, :error :high}
Alert: {:val 11, :error :high}
Tallystrix takes only numbers, "abc1000" was not acceptable.
Conclusion
(flow/stop asynctopolis)true(Thread/sleep 1)Randomius transitioning :clojure.core.async.flow/stop
Talon, rest!
Chronon transitioning :clojure.core.async.flow/stop
Chronon rests.
Tallystrix transitioning :clojure.core.async.flow/stop
Claxxus transitioning :clojure.core.async.flow/stop
nilIcarus realized that Flow is a library for building concurrent, event-driven systems out of simple, communication-free functions. Processes connect through channels. You define the structure as a directed graph. Flow takes care of orchestration. Flows are data-driven, easy to inspect, reason about and visualize. Then he wondered just how high could he fly?
Happy flowing, and keep your feathers waxed!