DAG visualization and static forecast¶
IronFlow combines a static planner (pre-run graph forecast) with a run DAG tab in the local UI so you can inspect wide and long flows without scrolling through hundreds of identical boxes.
What is the DAG?¶
The run DAG (directed acyclic graph) shows task dependencies for a single flow run:
- Nodes — tasks or task runs (depending on view mode).
- Edges — dependency arrows pointing downstream (from prerequisites to dependents).
- Layout — dependencies always flow left → right; parallel siblings at the same depth stack top → bottom (both view modes).
View modes¶
The UI exposes two views. API query parameter names are unchanged (mode=logical | mode=expanded).
| UI label | API mode |
What you see |
|---|---|---|
| Aggregated fan-out | logical |
Planned graph from the static forecast. One node per forecast step; map() fan-out is collapsed into a single node. Repeated submit calls appear as separate planned steps (task-0, task-1, …). |
| Task runs | expanded |
One node per task execution — every mapped child, every submit invocation, with run id suffix on the label. |
Use Aggregated fan-out to understand structure; use Task runs to debug individual executions at scale (with zoom, pan, and search).
Static forecast (static-planner/)¶
When a @flow starts, IronFlow compiles the flow function source into a manifest (nodes + edges) and a forecast (task count, critical path, parallelism). This powers the Aggregated fan-out DAG mode and assigns planned_node_id values to task runs at execution time.
What the planner analyzes¶
task.submit(...)andtask.map(...)inside the@flowbodywait_for=[...]dependency lists- Constant bounded loops:
for i in range(3): ... @task(name="custom")— resolved viaTaskWrapperobjects visible on the flow module or in the flow closure- Repeated calls to the same task — each call becomes a separate node labeled
task-0,task-1, … - Distinct wrappers on a shared function — e.g.
task(name="ping-start")(fn)andtask(name="ping-end")(fn)are separate nodes
Fallback to runtime¶
When analysis cannot see the shape (dynamic range(n), if branches, tasks not visible to the compiler), the manifest is marked fallback_required and the UI builds a runtime-inferred DAG from recorded task runs. Labels still use task-N instance suffixes where possible.
Run detail → DAG tab¶
Open any flow run → DAG tab.
| Control | Behavior |
|---|---|
| Aggregated fan-out | Planned graph; map() fan-out collapsed |
| Task runs | One node per task execution |
| Fit / Reset | Fit graph to viewport or reset zoom |
| Search | Match task id, label, or name; zoom to selection; Enter cycles multiple matches |
| Click node | Focus and highlight upstream + downstream path |
| Double-click | On an inline_subflow node with a child run id, open that child run detail |
| Scroll / drag | Zoom toward cursor; pan the canvas |
Subflow node kinds¶
When a flow nests children (see How to compose flows with subflows), the DAG may include:
kind |
Meaning | Typical styling |
|---|---|---|
inline_subflow |
Blocking inline child flow (M1) | Dashed border; expand / navigate to child run |
subflow_task |
Deployment-backed subflow surrogate task (M2) | Solid accent; links to child flow run when available |
Parent run detail also lists children[] (id, name, state, execution_mode, depth) for breadcrumb navigation.
A definition line under the toolbar restates the active view and layout: “Dependencies: left → right · parallel tasks: top → bottom”.
Seed large graphs for manual testing¶
With the API on http://127.0.0.1:8000:
curl -X POST http://127.0.0.1:8000/benchmark/run \
-H 'Content-Type: application/json' \
-d '{"flavor":"wide","complexity":100}'
curl -X POST http://127.0.0.1:8000/benchmark/run \
-H 'Content-Type: application/json' \
-d '{"flavor":"long_chain","complexity":100}'
Then open the run in the UI at http://localhost:4173/runs and use the DAG tab. See Optional: verify the web UI for the full checklist.
API¶
GET /api/flow-runs/{id}/dag?mode=logical|expanded— DAG nodes, edges, forecast metadata,source(forecastorruntime), and warnings.logical= Aggregated fan-out / planned graphexpanded= per task run
Task runs expose planned_node_id when the forecast could assign one; the UI uses this to color Aggregated fan-out nodes during live updates.