|
8 | 8 |
|
9 | 9 | (ns ^{:author "Rich Hickey"}
|
10 | 10 | clojure.core.async.flow
|
11 |
| - "A library for building concurrent, event driven data processing |
| 11 | + " |
| 12 | + Note - Alpha, work-in-progress, names and other details are in flux |
| 13 | +
|
| 14 | + A library for building concurrent, event driven data processing |
12 | 15 | flows out of communication-free functions, while centralizing
|
13 | 16 | control, reporting, execution and error handling. Built on core.async.
|
14 | 17 |
|
|
18 | 21 | a set of channels for centralized control, reporting, error-handling,
|
19 | 22 | and execution of the processes
|
20 | 23 |
|
21 |
| - A flow is constructed from flow definition data which defines a |
| 24 | + A flow is constructed from flow configuration data which defines a |
22 | 25 | directed graph of processes and the connections between
|
23 | 26 | them. Processes describe their I/O requirements and the
|
24 | 27 | flow (library) itself creates channels and passes them to the
|
25 | 28 | processes that requested them. See 'create-flow' for the
|
26 |
| - details. The flow definition provides a centralized place for policy |
27 |
| - decisions regarding configuration, threading, buffering etc. |
| 29 | + details. The flow configuration provides a centralized place for |
| 30 | + policy decisions regarding process settings, threading, buffering etc. |
28 | 31 |
|
29 |
| - It is expected that applications will rarely define processes but |
30 |
| - instead use the API functions here, 'process' and 'step-process', |
31 |
| - that implement the process protocol in terms of calls to ordinary |
32 |
| - functions that include no communication or core.async code. In this |
33 |
| - way the library helps you achieve a strict separation of your |
34 |
| - application logic from its execution, communication, lifecycle and |
35 |
| - monitoring. |
| 32 | + It is expected that applications will rarely define instances of the |
| 33 | + process protocol but instead use the API functions here, 'process' |
| 34 | + and 'step-process', that implement the process protocol in terms of |
| 35 | + calls to ordinary functions that might include no communication or |
| 36 | + core.async code. In this way the library helps you achieve a strict |
| 37 | + separation of your application logic from its execution, |
| 38 | + communication, lifecycle, error handling and monitoring. |
36 | 39 |
|
37 | 40 | Note that at several points the library calls upon the user to
|
38 | 41 | supply ids for processes, inputs, outputs etc. These should be
|
|
52 | 55 | (set! *warn-on-reflection* true)
|
53 | 56 |
|
54 | 57 | (defn create-flow
|
55 |
| - "Creates a flow from the supplied definition: a map containing the |
| 58 | + "Creates a flow from the supplied configuration: a map containing the |
56 | 59 | keys :procs and :conns, and optionally :mixed-exec/:io-exec/:compute-exec
|
57 | 60 |
|
58 | 61 | :procs - a map of pid->proc-def
|
|
66 | 69 |
|
67 | 70 | :conns - a collection of [[from-pid outid] [to-pid inid]] tuples.
|
68 | 71 |
|
69 |
| - Inputs and outputs support mutliple connections. When an output is |
| 72 | + Inputs and outputs support multiple connections. When an output is |
70 | 73 | connected multiple times every connection will get every message,
|
71 | 74 | as per a core.async/mult.
|
72 | 75 |
|
73 | 76 | :mixed-exec/:io-exec/:compute-exec -> ExecutorService
|
74 | 77 | These can be used to specify the ExecutorService to use for the
|
75 |
| - corresonding context, in lieu of the lib defaults |
| 78 | + corresonding workflow, in lieu of the lib defaults. |
76 | 79 |
|
77 | 80 | N.B. The flow is not started. See 'start'"
|
78 |
| - [def] (impl/create-flow def)) |
| 81 | + [config] (impl/create-flow config)) |
79 | 82 |
|
80 | 83 | (defn start
|
81 | 84 | "starts the entire flow from init values. The processes start paused.
|
82 | 85 | Call 'resume' or 'resume-proc' to start flow. returns a map with keys:
|
83 | 86 |
|
84 |
| - ::flow/report-chan - a core.async chan for reading.'ping' reponses |
| 87 | + :report-chan - a core.async chan for reading.'ping' reponses |
85 | 88 | will show up here, as will any explicit ::flow/report outputs
|
86 | 89 | from :transform/:introduce
|
87 | 90 |
|
88 |
| - ::flow/error-chan - a core.async chan for reading. Any (and only) |
| 91 | + :error-chan - a core.async chan for reading. Any (and only) |
89 | 92 | exceptions thrown anywhere on any thread inside a flow will appear
|
90 | 93 | in maps sent here. There will at least be a ::flow/ex entry with the
|
91 | 94 | exception, and may be additional keys for pid, state, status etc
|
|
144 | 147 |
|
145 | 148 | :describe - required, () -> desc
|
146 | 149 | where desc is a map with keys :params :ins and :outs, each of which
|
147 |
| - in turn is a map of keyword to doc string |
| 150 | + in turn is a map of keyword to doc string, and :workload with |
| 151 | + possible values of :mixed :io :compute. All entries in the describe |
| 152 | + return map are optional. |
148 | 153 |
|
149 | 154 | :params describes the initial arguments to setup the state for the function.
|
150 | 155 | :ins enumerates the input[s], for which the flow will create channels
|
151 | 156 | :outs enumerates the output[s], for which the flow may create channels.
|
| 157 | + :workload - describes the nature of the workload, one of :mixed :io or :compute |
| 158 | + an :io workload should not do extended computation |
| 159 | + a :compute workload should never block |
152 | 160 |
|
153 |
| - No key may be present in both :ins and :outs The ins/outs/params of f |
154 |
| - will be the ins/outs/params of the process. describe may be called |
155 |
| - by users to understand how to use the proc. It will also be called |
156 |
| - by the impl in order to discover what channels are needed. |
| 161 | + No key may be present in both :ins and :outs, allowing for a uniform |
| 162 | + channel coordinate system of [:process-id :channel-id]. The |
| 163 | + ins/outs/params returned will be the ins/outs/params of the |
| 164 | + process. describe may be called by users to understand how to use |
| 165 | + the proc. It will also be called by the impl in order to discover |
| 166 | + what channels are needed. |
157 | 167 |
|
158 | 168 | :init - optional, (arg-map) -> initial-state
|
159 | 169 |
|
|
199 | 209 | for introduce to return with no output. Do not spin poll in the introduce
|
200 | 210 | fn.
|
201 | 211 |
|
202 |
| - proc accepts an option map with keys: |
203 |
| - :exec - one of :mixed, :io or :compute, default :mixed |
204 |
| - :compute-timeout-ms - if :exec is :compute, this timeout (default 5000 msec) |
| 212 | + process accepts an option map with keys: |
| 213 | + :workflow - one of :mixed, :io or :compute |
| 214 | + :compute-timeout-ms - if :workflow is :compute, this timeout (default 5000 msec) |
205 | 215 | will be used when getting the return from the future - see below
|
206 | 216 |
|
207 |
| - The :compute context is not allowed for proc impls that |
| 217 | + A :workflow supplied as an option to process will override |
| 218 | + any :workflow returned by the :describe fn of the process. If neither |
| 219 | + are provded the default is :mixed. |
| 220 | +
|
| 221 | + The :compute workload is not allowed for proc impls that |
208 | 222 | provide :introduce (as I/O is presumed).
|
209 | 223 |
|
210 |
| - In the :exec context of :mixed or :io, this dictates the type of |
| 224 | + In the :workflow context of :mixed or :io, this dictates the type of |
211 | 225 | thread in which the process loop will run, _including its calls to
|
212 | 226 | transform/introduce_.
|
213 | 227 |
|
|
223 | 237 |
|
224 | 238 | When :compute is specified transform must not block!"
|
225 | 239 | ([process-impl-map] (process process-impl-map nil))
|
226 |
| - ([process-impl-map {:keys [exec timeout-ms] |
227 |
| - :or {exec :mixed, timeout-ms 5000} :as opts}] |
| 240 | + ([process-impl-map {:keys [workflow timeout-ms] |
| 241 | + :or {timeout-ms 5000} :as opts}] |
228 | 242 | (impl/proc process-impl-map opts)))
|
229 | 243 |
|
230 | 244 | (defn step-process
|
|
248 | 262 | (process {:describe f, :init f, :transform f} opts)))
|
249 | 263 |
|
250 | 264 | (defn futurize
|
251 |
| - "Takes a fn f and returns a fn that takes the same arguments as f and |
252 |
| - immediately returns a future, having starting a thread of the |
253 |
| - indicated type, or via the supplied executor, that invokes f with |
254 |
| - those args and completes that future with its return. |
| 265 | + "Takes a fn f and returns a fn that takes the same arguments as f |
| 266 | + and immediately returns a future, having started a thread for the |
| 267 | + indicated workload, or via the supplied executor, that invokes f |
| 268 | + with those args and completes that future with its return. |
255 | 269 |
|
256 | 270 | futurize accepts kwarg options:
|
257 |
| - :exec - one of :mixed, :io, :compute |
| 271 | + :exec - one of the workloads :mixed, :io, :compute |
258 | 272 | or a j.u.c.ExecutorService object,
|
259 | 273 | default :mixed"
|
260 | 274 | [f & {:keys [exec]
|
|
0 commit comments