Parallel by Default
When steps have no relationship between them, they run concurrently. Timbal doesn’t wait for one to finish before starting the next:Context Access
The input and output from each step is stored in its Run Context, accessible viaget_run_context(). Each step exposes two built-in variables:
.input: Contains a dictionary of all the parameters passed to the step. They are accessed through their name..output: Contains the value(s) returned by the step. Can be a single value, dictionary, array, or custom class.
| Method | Description |
|---|---|
current_span() | Current step’s data |
parent_span() | Parent workflow’s data |
step_span("name") | Any sibling step’s data |
Custom Variables
You can also create your own custom variables to share data between steps:process_user:
check_status:
Data Dependencies
When a step parameter references another step’s output via a lambda, Timbal automatically creates a dependency and enforces sequential execution:fetch_usersandfetch_ordersrun in parallel (no dependencies between them)merge_resultswaits for both to complete (its parameters reference their outputs)
fetch_users and fetch_orders haven’t executed when merge_results is defined, Timbal detects the step_span() references and knows to wait.
Handling Optional Steps
When a step might be skipped (e.g., due to awhen condition), you need to safely handle cases where that step didn’t execute. Use default=None with step_span() to check if a step ran before accessing its output.
Execution Flow
Consider a workflow that validates data and then processes it differently based on the validation result:merge_results tries to access process_valid or process_invalid, one of them won’t exist because it was skipped. Without default=None, accessing a skipped step would raise an error.
The Solution: Use step_span("name", default=None) which returns None if the step was skipped, allowing you to check which step actually ran.
Example
validate_dataalways executes and returns{"valid": True}or{"valid": False}- Based on the validation result, either
process_validorprocess_invalidruns (but never both) merge_resultsusesstep_span("name", default=None)to safely check which processing step ran:- If
step_span("process_valid", default=None)returns a span (notNone), that step ran - If it returns
None, the step was skipped, so we checkprocess_invalidinstead
- If
Key Point:
step_span("name", default=None) returns None if the step was skipped, allowing you to handle optional dependencies gracefully. Without default=None, accessing a skipped step would raise an error.Explicit Dependencies
Usedepends_on when you need ordering without a data dependency:
process_data waits for init_database even though it doesn’t use its output.
Summary
- Steps run in parallel by default
- Access sibling step data via
step_span(), custom variables viacurrent_span() - Lambda parameters automatically create dependencies — even if the referenced step hasn’t executed yet
- Use
depends_onfor explicit ordering without data dependency