Orchestration Constructs
Canonical reference for non-step flow forms and metadata labels used for readable orchestration timelines.
Quick Answer
Use standard flow forms (if, for, loop, cond, case, etc.) inside :flow, and annotate control nodes with metadata labels (^{:label ...}) so runs render human-readable branch and loop names.
Supported Non-Step Forms
- sequencing:
let,do - branching:
if,if-not,when,when-not,cond,case - iteration:
for,doseq,loop,recur - child orchestration:
flow/call-flow
Label Metadata
Attach metadata directly to a control form:
- shorthand:
^"My Label" (if ...) - explicit:
^{:label "My Label"} (if ...)
Branch-specific labels on if / if-not:
^{:label "Risk gate"
:yes "Requires approval"
:no "Auto-approve"}
(if (:needs-approval summary)
(flow/step :wait :approval {...})
{:action :approve})
Loop metadata:
^{:label "Retry status poll" :max-iterations 6}
(loop [attempt 0]
(let [status (flow/step :http :get-status
{:connection :orders-api
:method :get
:path "/orders/status"})]
(if (or (= :done (:state status))
(>= attempt 5))
status
(recur (inc attempt)))))
for / doseq label example:
^{:label "Enrich each order"}
(for [order orders]
(flow/step :http :enrich-order
{:connection :orders-api
:method :get
:path (str "/orders/" (:id order))}))
Branching Guidance
- use
if/if-notfor binary business gates and set:yes/:no - use
when/when-notfor one-sided conditionals - use
cond/casefor multi-branch routing; add^{:label ...}on the whole form - keep transformation logic in top-level
:functions, not inside branch bodies
Design Rules
- label major decisions and loops; skip labels only for trivial one-liners
- keep labels business-facing ("Approve order?", "Retry payment status")
- keep
:flowfocused on orchestration, and call steps/functions/templates for heavy logic/data - combine labels with
:persistand templates to keep large flows readable and size-safe - use
flow/pollfor bounded external status polling instead of custom unbounded loops