Skip to content

Control Flow

Processing Framework supports conditional control flow within a Procedure through a special system Operation called the Switcher. The Switcher evaluates condition expressions against Procedure and Execution parameters and determines which downstream Operations get executed.

This enables building Procedures that can take different processing paths depending on runtime values, without needing to create separate Procedures for each scenario.

The Switcher Operation acts as a routing mechanism in a Procedure’s data flow. It evaluates one or more condition expressions and, for each condition that evaluates to True, makes the corresponding output port available. Downstream Operations connected to available output ports are executed as normal. Downstream Operations connected to unavailable output ports are removed from the Procedure execution entirely, along with any further Operations that depend on them.

Key behaviors:

  • Zero or more output ports can become available, depending on how many conditions evaluate to True.
  • Multiple conditions can be True simultaneously, allowing parallel branches to execute.
  • If no conditions evaluate to True, none of the Switcher’s downstream branches execute.
  • The Switcher itself does not produce data. It forwards data from upstream Operations through its output ports.
  • Removal of branches is transitive: if a removed Operation’s output is consumed by another Operation, that Operation is also removed, and so on down the chain.

A Switcher Operation is defined within a Procedure’s operations section. It uses the reserved identifier switcher and has a structure similar to a regular Operation with some important additions.

{
"branch": {
"identifier": "switcher",
"version": 1,
"name": "Switcher",
"description": "Implements Procedure Logic flow control.",
"inputs": {
"flow_control": {
"sources": [
"upstream_op_a:output",
"upstream_op_b:output"
]
}
},
"outputs": {
"case_1": {
"condition": "my_parameter == True",
"sources": [
"upstream_op_a:output"
]
},
"case_2": {
"condition": "my_parameter == False",
"sources": [
"upstream_op_b:output"
]
},
"case_3": {
"condition": "another_parameter == True"
}
}
}
}

The inputs section defines which upstream Operation outputs are available for the Switcher to forward. These act as aliases, they make upstream data available as potential outputs of the Switcher. At least one input source is required.

Each entry in the outputs section defines a conditional output port (a “case”). Each case has:

FieldRequiredDescription
conditionYesA condition expression that is evaluated at execution time.
sourcesNoWhich input port’s data to provide as the output for this case. If omitted, the port acts as a signal without forwarding data.
data_typeNoThe type of data output. Typically set to "*".

If the condition evaluates to True, the output port becomes available and downstream Operations connected to it will execute. If it evaluates to False, the port is absent and downstream Operations are removed.

Condition expressions are strings that get evaluated at execution time. They support comparisons, logical operators, and references to Procedure parameters, Execution parameters, and Operation output parameters.

OperatorDescription
==Equals
!=Not equal to
<Less than
<=Less than or equal to
>Greater than
>=Greater than or equal to
OperatorDescription
andLogical AND, both sides must be true
orLogical OR, at least one side must be true
WordDescription
TrueBoolean true value
FalseBoolean false value

Variables are unquoted strings that reference parameter values. They must be resolvable at execution time or an error will be thrown.

  • Procedure or Execution parameters: Use the parameter name directly (e.g., my_param).
  • Operation output parameters: Use the format operation_name:parameter_name (e.g., my_op:result).

A standalone variable name without any comparison operator is treated as NAME == True. For example, the condition IS_ENABLED is equivalent to IS_ENABLED == True.

  • Strings: Must be quoted. Use single quotes to avoid escaping issues in JSON (e.g., 'my_value').
  • Numbers: Both integers and decimals are supported, including negative numbers. They must not be quoted (e.g., 42, 3.14, -10).

Parentheses are fully supported for controlling evaluation priority.

"condition": "a == True or (b == False and c != 16)"

  • Parameter names and operation aliases that contain hyphens (-) are not supported. Use underscores (_) instead.
  • Arithmetic operations (+, -, *, /) are not supported in conditions.
  • List/array values cannot be compared directly.

Route processing to different branches based on a string parameter value. Only the branch whose condition matches the BRANCH parameter will execute.

{
"operations": {
"generate_file": {
"identifier": "my_file_generator",
"version": 1,
"inputs": {},
"outputs": {
"output": {
"data_type": "*"
}
}
},
"branch_switcher": {
"identifier": "switcher",
"version": 1,
"inputs": {
"flow_control": {
"sources": ["generate_file:output"]
}
},
"outputs": {
"case_1": {
"condition": "BRANCH == 'foo'",
"sources": ["generate_file:output"]
},
"case_2": {
"condition": "BRANCH == 'bar'",
"sources": ["generate_file:output"]
}
}
},
"foo_branch": {
"identifier": "my_processor",
"version": 1,
"inputs": {
"input": {
"sources": ["branch_switcher:case_1"]
}
}
},
"bar_branch": {
"identifier": "my_processor",
"version": 1,
"inputs": {
"input": {
"sources": ["branch_switcher:case_2"]
}
}
}
},
"parameters": {
"BRANCH": {
"default_value": "foo",
"description": "Controls which branch gets executed (foo or bar)"
}
}
}

Execution with default parameters (BRANCH = "foo"):

  • generate_file executes.
  • branch_switcher evaluates: case_1 condition "foo" == 'foo' is True, case_2 condition "foo" == 'bar' is False.
  • foo_branch executes (receives data from generate_file:output).
  • bar_branch is removed, it is not executed.

Execution with BRANCH = "bar":

  • generate_file executes.
  • foo_branch is removed.
  • bar_branch executes.

When conditions are independent, multiple branches can execute simultaneously. Here, two separate parameters control two separate branches.

{
"outputs": {
"case_1": {
"condition": "BRANCH == 'foo'",
"sources": ["generate_file:output"]
},
"case_2": {
"condition": "BRANCH2 == 'bar'",
"sources": ["generate_file:output"]
}
}
}

Execution with BRANCH = "foo" and BRANCH2 = "bar":

  • Both case_1 and case_2 evaluate to True.
  • Both downstream branches execute in parallel.

If no conditions evaluate to True, all downstream branches connected to the Switcher are removed. The Procedure still completes successfully, only Operations upstream of the Switcher and any Operations not connected to the Switcher execute.

{
"outputs": {
"case_1": {
"condition": "BRANCH == 'foo'",
"sources": ["generate_file:output"]
},
"case_2": {
"condition": "BRANCH2 == 'bar'",
"sources": ["generate_file:output"]
}
}
}

Execution with BRANCH = "something_else" and BRANCH2 = "something_else":

  • Neither condition matches.
  • generate_file executes (it is upstream of the Switcher).
  • foo_branch and bar_branch are both removed.
  • The Procedure finishes successfully with status FINISHED.

Conditions can use logical operators (and, or, !=) and parentheses. In this example, all four conditions evaluate to True when BOOL_TRUE = true and BOOL_FALSE = false.

{
"outputs": {
"and_case": {
"condition": "BOOL_TRUE and BOOL_TRUE",
"sources": ["generate_file:output"]
},
"neq_case": {
"condition": "BOOL_TRUE != BOOL_FALSE",
"sources": ["generate_file:output"]
},
"or_case": {
"condition": "BOOL_TRUE or BOOL_FALSE",
"sources": ["generate_file:output"]
},
"parentheses_case": {
"condition": "(BOOL_TRUE or BOOL_FALSE) and BOOL_TRUE",
"sources": ["generate_file:output"]
}
}
}
CaseConditionEvaluates To
and_casetrue and trueTrue
neq_casetrue != falseTrue
or_casetrue or falseTrue
parentheses_case(true or false) and trueTrue

Conditions support numeric comparisons using <, <=, >, >=. In this example, all four conditions evaluate to True when FLOAT = 42.1 and INT = 42.

{
"outputs": {
"gt_case": {
"condition": "FLOAT > INT",
"sources": ["generate_file:output"]
},
"gte_case": {
"condition": "FLOAT >= FLOAT",
"sources": ["generate_file:output"]
},
"lt_case": {
"condition": "INT < FLOAT",
"sources": ["generate_file:output"]
},
"lte_case": {
"condition": "INT <= INT",
"sources": ["generate_file:output"]
}
}
}
CaseConditionWith FLOAT=42.1, INT=42Evaluates To
gt_caseFLOAT > INT42.1 > 42True
gte_caseFLOAT >= FLOAT42.1 >= 42.1True
lt_caseINT < FLOAT42 < 42.1True
lte_caseINT <= INT42 <= 42True

Example 6: Combining Multiple Condition Types

Section titled “Example 6: Combining Multiple Condition Types”

Conditions can combine comparisons with logical operators and parentheses for more complex routing logic.

"condition": "ex_parameter >= 10 and proc_parameter == 'single'"
"condition": "a == True or (b == False and c != 16)"

The simplest possible conditions use the boolean literals directly:

"condition": "True"
"condition": "False"

A condition of "True" means the output port is always available. A condition of "False" means it is never available. These can be useful during development or testing.

Multiple Switcher Operations can be chained together within a single Procedure. The output of one Switcher can feed into a downstream Switcher, enabling multi-level conditional logic.

For example, a first Switcher might route based on a high-level parameter, and a second Switcher within one of those branches might further subdivide the flow based on a more specific parameter.

When chaining Switchers, the transitive removal behavior still applies: if a parent Switcher’s condition evaluates to False, all downstream Operations, including any chained Switchers and their branches, are removed.