-
Notifications
You must be signed in to change notification settings - Fork 0
How To Build a Pipeline
Use a pipeline when you want to compose nodes into a larger executable graph.
GraphK provides three main public pipeline forms:
SequencePipeBranchPipeMultiPipe
In most cases, start with SequencePipe.
A pipeline is also a Node, but instead of doing one piece of work directly, it coordinates traversal across child nodes or nested pipelines.
This means:
- pipelines can be nested
- pipelines can carry context and policies
- pipelines can be executed manually
- pipelines are usually executed through
Runneror throughEmitterafter registration in aProgram
graphk.Pipeline is the base type. It is usually not instantiated directly.
Important public methods:
add(node, index=None)start(session)step()complete()sequence()forward()
The one abstract method is:
forward()
forward() defines traversal order. Concrete pipeline classes implement it differently.
Use SequencePipe when execution should happen in order.
Simple example:
import graphk
pipeline = graphk.SequencePipe(
nodes=[
graphk.demo.IncrementNode("A", increment=1, target_key="total", response=True),
graphk.demo.IncrementNode("B", increment=2, target_key="total", response=True),
graphk.demo.IncrementNode("C", increment=3, target_key="total", response=True),
]
)This is the default composition type for GraphK.
Pipelines can contain other pipelines.
Example:
import graphk
inner = graphk.SequencePipe(
nodes=[
graphk.demo.IncrementNode("Inner-A", increment=2, target_key="total", order_key="order", response=True),
graphk.demo.IncrementNode("Inner-B", increment=3, target_key="total", order_key="order", response=True),
]
)
outer = graphk.SequencePipe(
nodes=[
graphk.demo.IncrementNode("Outer-Start", increment=1, target_key="total", order_key="order", response=True),
inner,
graphk.demo.IncrementNode("Outer-End", increment=4, target_key="total", order_key="order", response=True),
]
)This is the normal way to build larger execution graphs from smaller reusable pieces.
Use BranchPipe when exactly one matching route should execute.
Main inputs:
nodestestsselection_policy
Each branch item should itself be a pipeline.
Example shape:
import graphk
branch = graphk.BranchPipe(
selection_policy=graphk.BranchPipe.SELECT_FIRST,
nodes=[
graphk.SequencePipe(nodes=[graphk.demo.RouteNode("A")]),
graphk.SequencePipe(nodes=[graphk.demo.RouteNode("B")]),
],
tests=[
graphk.Matcher(task="route", route="alpha"),
graphk.Matcher(task="route", route="beta"),
],
)Use SELECT_FIRST unless you explicitly want random selection.
Use MultiPipe when all matching routes should execute.
Example shape:
import graphk
pipe = graphk.MultiPipe(
order_policy=graphk.MultiPipe.ORDER_STORED,
nodes=[
graphk.SequencePipe(nodes=[graphk.demo.RouteNode("A")]),
graphk.SequencePipe(nodes=[graphk.demo.RouteNode("B")]),
],
tests=[
graphk.Matcher(task="route"),
graphk.Matcher(task="route"),
],
)Low-level lifecycle:
- create a session
- call
session.start() - call
pipeline.start(session) - iterate nodes from the pipeline
- call
pipeline.step()until each node finishes - call
pipeline.complete()
Example:
import graphk
pipeline = graphk.SequencePipe(
nodes=[
graphk.demo.IncrementNode("A", increment=1, target_key="counter"),
graphk.demo.IncrementNode("B", increment=2, target_key="counter"),
]
)
session = graphk.Session(counter=0)
session.start()
pipeline.start(session)
for node in pipeline:
node.start(session)
while True:
try:
pipeline.step()
except StopIteration:
node.complete()
break
pipeline.complete()
print(session.to_dict())Prefer Runner or Emitter instead of manual stepping.
Recommended pattern:
import graphk
pipeline = graphk.SequencePipe(nodes=[...])
session = graphk.Session(...)
runner = graphk.Runner(pipeline, session)
runner.start()
runner.run()
print(session.to_dict())Program-dispatch pattern:
import graphk
pipeline = graphk.SequencePipe(nodes=[...])
program = graphk.Program({"main": pipeline})
emitter = graphk.Emitter(program)
session = emitter.request("main", graphk.Session(...))
print(session.to_dict())If the program has one registered pipeline, or a configured default, the emitter can dispatch without an explicit id:
session = emitter.request(session=graphk.Session(...))- Do not instantiate
Pipelinedirectly unless you are implementing a custom subclass. - Do not put plain nodes directly into
BranchPipebranches; use branch pipelines. - Do not manually manage traversal when
Runneralready fits the use case. - Do not confuse
sequence()with execution;sequence()resolves traversal order, it does not run the pipeline.
Recommended references: