Workflows Execution Engine in Detail
The compilation process creates a Workflow Execution graph, which holds all the necessary details to run a Workflow definition. In this section, we will explain the details of the execution process.
At a high level, the process does the following:
- Validates runtime input: checks that all required placeholders are filled with data and ensures the data types are correct.
- Determines execution order: defines the order in which steps are executed.
- Prepares step inputs and caches outputs: organizes the inputs for each step and saves the outputs for future use.
- Builds the final Workflow outputs: assembles the overall result of the Workflow.
Validation of Runtime Input
The Execution Engine has a dedicated component that parses and prepares the input for use. It recognizes batch-oriented inputs from the Workflow definition and converts them into an internal representation (e.g., WorkflowImage becomes Batch[WorkflowImageData]). Non-batch-oriented parameters are checked for type consistency against the block manifests.
All batch-oriented inputs must have a size of either 1 or n. When a batch contains only a single element, it is automatically broadcasted across the entire batch.
Determining Execution Order
The Workflow Execution Graph is a directed acyclic graph (DAG), which allows us to determine the topological order. Topological order refers to a sequence in which Workflow steps are executed, ensuring that each step's dependencies are met before it runs.
Additionally, the topological structure allows us to identify which steps can be executed in parallel without causing race conditions. Parallel execution is the default mode in the Workflows Execution Engine.
Due to the parallel execution mode in the Execution Engine, we strongly urge all block developers to avoid mutating any data passed to the block's run(...) method. If modifications are necessary, always make a copy of the input object before making changes.
Handling Step Inputs and Outputs
SIMD vs Non-SIMD Steps
A SIMD (Single Instruction, Multiple Data) step processes batch-oriented data, where the same operation is applied to each data point. The output from such a step is expected to be a batch of elements, preserving the order of the input batch elements.
Non-SIMD steps, by contrast, deliver a single result for the input data. In the case of non-SIMD flow-control steps, they affect all downstream steps as a whole.
Starting with Execution Engine v1.6.0, Auto Batch Casting was introduced:
- When a SIMD input is detected but receives scalar data, the Execution Engine automatically casts it into a batch.
- The dimensionality of the batch is determined at compile time, using lineage information from other batch-oriented inputs when available.
- Outputs are evaluated against the casting context — leaving them as scalars when the block keeps or decreases output dimensionality, or creating new batches when an increase of dimensionality is expected.
Preparing Step Inputs
The Execution Engine maintains indices for each batch-oriented data point. For example:
- An input images batch of four elements will be indexed
[(0,), (1,), (2,), (3,)]. - A block that increases dimensionality (e.g., Dynamic Crop with 2 crops for the first image, 1 for the second, and 3 for the fourth) would be indexed:
[(0, 0), (0, 1), (1, 0), (3, 0), (3, 1), (3, 2)].
Indexing ensures that all batch-oriented inputs are synchronized. The Execution Engine will always ship prediction (3,) with image (3,) and the corresponding batch of crops [(3, 0), (3, 1), (3, 2)].
Conditional Execution
Flow-control blocks manage which steps should be executed based on certain conditions. During compilation, steps affected by these conditions are flagged. When constructing their inputs, a mask for flow-control exclusion is applied. By default, blocks don't accept empty values, so any None at a given index in a batch will cause that index to be excluded from processing.
Managing Flow-Control Steps Outputs
The outputs of flow-control steps create execution branches. Each branch has an associated mask:
- For SIMD branches, the mask contains a set of indices that will remain active for processing.
- For non-SIMD branches, the mask is a simple
True/Falsevalue.
Caching Steps Outputs
Data processing steps require attention to ensure their results are correctly passed to other steps. The key aspect is properly indexing the outputs. If the dimensionality changes during processing, the Execution Engine either uses the high-level index or creates nested dimensions dynamically.
Building Workflow Outputs
For details on how outputs are constructed, please refer to the Workflow Definitions page and the Output Construction section of the Workflow Execution documentation.