Types & Safety Semantics
The isPure and isIdempotent flags on function blocks are the foundation of the engine's transaction model. They determine how the engine handles failures, retries, and execution classification.
Safety Properties
| Property | Meaning | Example |
|---|---|---|
isPure: true |
No side effects at all | Collecting show version, reading facts |
isIdempotent: true |
Same input → same result, safe to re-run | Writing a complete config (not appending), setting a description |
Both false |
Side effects that may not be safely repeated | Incrementing a counter, appending to a log, rebooting a device |
Pure
A pure function block only reads data. It never modifies the device, the CMS, or any external system. If a pure function block fails, nothing has changed -- the world is exactly as it was before.
The engine uses this to classify failures: if a workflow only ran pure steps before failing, the failure is FAILED_SAFE.
Idempotent
An idempotent function block can be safely executed multiple times with the same input. The result is the same whether it runs once or ten times. This is a weaker guarantee than pure (the function block does have side effects), but the side effects are predictable and repeatable.
The engine tracks idempotency (isIdempotentExecution) throughout a workflow execution but does not yet use it for automatic retry decisions. This is planned for a future release.
Transaction Classification
The engine tracks the safety properties of all executed steps throughout a workflow execution:
graph LR
subgraph tracking ["Engine tracks during execution"]
IPE["isPureExecution<br/>(all steps were pure)"]
IIE["isIdempotentExecution<br/>(all steps were pure or idempotent)<br/>(tracked, not yet used for decisions)"]
end
| All executed steps are... | isPureExecution |
isIdempotentExecution |
On failure → |
|---|---|---|---|
| Pure | true |
true |
FAILED_SAFE |
| Pure or idempotent | false |
true |
Retry eligible, then FAILED_UNSAFE |
| Mix (some neither) | false |
false |
FAILED_UNSAFE |
Implementation status
Today: Only isPureExecution drives the failure classification. If all executed
steps were pure → FAILED_SAFE; otherwise → FAILED_UNSAFE. The "retry eligible" path
for idempotent executions is planned but not yet active. isIdempotentExecution is
tracked throughout execution but not yet used for automatic retry decisions.
The flags are set by the function block developer
The engine trusts the isPure and isIdempotent flags declared during registration.
If a function block claims to be pure but actually modifies data, the engine will
incorrectly classify failures as FAILED_SAFE. Accurate declarations are essential
for the transaction model to work correctly.
Automatic Retry (Planned)
Not Yet Implemented
Automatic retry based on purity/idempotency flags is not yet implemented. The engine
tracks these properties but does not use them for retry decisions. Both automatic retries
and the step-level retryConfig are planned for a future release.
When implemented, automatic retries will work as follows:
- A job fails
- The engine checks if the function block is
isPureorisIdempotent - If so and the retry limit has not been reached, a new job is created automatically
This will handle transient failures (SSH timeouts, temporary network partitions) without requiring explicit retryConfig on every step.
Best Practices for Workflow Authors
Know your function blocks:
: Check the isPure and isIdempotent flags of the function blocks you use. This tells you what the engine will do if something goes wrong.
Order for safety:
: Put pure steps (data collection, validation) before configuration steps. If the workflow fails during the pure phase, it is automatically FAILED_SAFE.
Design idempotent configs: : When writing configuration function blocks, prefer declarative (replace entire config section) over imperative (append line). Declarative configs are naturally idempotent.
Use FAILED_SAFE as a signal:
: If your workflows frequently end as FAILED_SAFE, that means your read-only steps are failing (likely connectivity issues) but nothing harmful happened. Investigate the root cause but don't panic.
See also:
- Pure and Idempotent (Worker SDK) -- How to declare and reason about
is_pure/is_idempotentin Python - Workflow as a Transaction -- How purity and idempotency drive the engine's transaction model