Skip to main content

Dependencies between Steps

We have previously seen how to access the Run Context to store additional data of the run. Additionally, steps can access the data from their parent run or neighbour steps within the workflow.
  • current_span() - Access the current step’s data
  • parent_span() - Access the parent workflow’s data
  • step_span("step_name") - Access any specific neighbour step’s data
Referencing data from another run creates dependencies within the Workflow. Timbal automatically resolves these dependencies to ensure proper execution.

Default Execution

Steps run in parallel by default. If one step produces an output needed by another, the framework automatically enforces sequential execution between those steps. The dependency is resolved under the hood.
import asyncio
from timbal import Workflow

async def func_1(x: str):
    asyncio.sleep(1)
    return x

async def func_2(y: str):
    asyncio.sleep(10)
    return y

async def func_3():
    return get_run_context().step_span("func_1").output    # output from func_1

workflow = (Workflow(name='my_workflow')
    .step(func_1, x="a")
    .step(func_2, y="b")
    .step(func_3)
)
In this example, we have:
  • func_1 and func_2 run concurrently.
  • func_3 starts only after func_1 has finished.
  • The workflow’s final output will be b, since func_2 it is the last to finish.

Forcing Sequential Execution

Steps can be run sequentially even if there is no data dependency with depends_on parameter.
workflow = (Workflow(name='my_workflow')
    .step(func_1, x="a")
    .step(func_2, y="b", depends_on=[func_1])
    .step(func_3)
)
Now, both steps func_2and func_3 must wait for func_1 to finish.

Summary

  • Parallel execution by default.
  • Sequential execution is applied automatically when parameter dependencies exist between steps.
  • Sequential execution can be enforced with depends_on.