Graph Procedure Composition
Great! Now Graph Procedures have given us free concurrency just by structuring our code declaratively rather than imperatively. But as we'd realistically only want to put a few nodes in a single Graph Procedure from a code maintenance and readability point of view, how do we write DAGS that are larger than just a few nodes? Composition! By this I mean simply calling another Graph Procedure from within the current one.
For Example:
Fig 1:
graph function bar(argB: int, argC: C) -> future<BarRes> {
root barRes <- doBar(@barA);
node barA <- doBarA(@barB, @barC);
node barB <- doBarB(argB);
node barC <- doBarC(argC);
}
graph TD barC(barC) --> barA barB(barB) --> barA barA(barA) --> barRes
Fig 2:
graph function foo(argA: A) -> future<FooRes> {
root fooRes <- doFoo(@fooA, @fooB);
node fooA <- doFooA(@fooC);
node fooB <- bar(10, @fooC); # <-- Graph Composition via Call to `bar`.
node fooC <- doFooC(argA);
}
graph TD fooC --> fooA fooC --> fooB fooB --> fooRes fooA --> fooRes
Because foo(...)
includes a call to bar(...)
as a subgraph, you can imagine that node fooB
in graph foo
actually
composes around the entire bar
graph.
graph TD fooC --> fooA fooC --> barC barRes --> fooRes subgraph fooB barC --> barA barB --> barA barA --> barRes end fooA --> fooRes
This composition is extremely simple to understand in this way. The entire subgraph is started after all data dependencies of the node wrapping it are ready.