Skip to main content
Version: 1.0.8

Execution & Triggering

What starts a pipeline​

TriggerNodeFires when
ScheduleInjectAn interval elapses or a cron expression matches
StartupInjectThe pipeline starts
Tag changeIndustrial I/O (subscribe)A subscribed tag changes
Alarm eventAlarm (subscribe)An alarm is raised, cleared or acknowledged
HTTP requestREST API (ingress)A matching request arrives
Another pipelineLink (ingress)A linked egress node in the same project sends
A message 1.0.8Message InA pipeline, a screen or a script sends on a matching subject
Manual—The Run button

A pipeline must be running for its triggers to be armed. Manual execution runs the graph once regardless.

Message flow​

┌─ copy → Node B ─┐
Node A ───┤ ├→ Node D runs once, with B's and C's results
└─ copy → Node C ─┘
  • A node runs when a message arrives on its input.
  • Multiple outbound wires fan out — each downstream branch receives the message. They run independently; one failing does not stop the others.
  • Multiple inbound wires converge. Within one run, a node fed by several wires waits until every one of its inputs has settled, then runs once with the results of all of them. If some branches failed or were skipped, it runs with the ones that delivered; only when none delivered is it skipped. A Debug node is the exception: it shows each input as it arrives.
  • A node returning nothing (None/null) ends that branch — a clean way to filter.

Execution context​

Each execution carries an identity used for logging, correlation and lifetime:

FieldMeaning
Execution IDOne traversal of the graph
Pipeline ID / projectWhere it ran
TriggerWhat started it
Start / end time, statusOutcome

Per-node results are recorded against the execution, which is what makes a failed run reconstructable after the fact.

Timeouts​

ScopeSetting
Python nodetimeout in node configuration, default 60 s
REST nodetimeout, default 30 s
Database transactiontimeoutMs, server-side auto-rollback
REST ingress routeRoute timeout, default 30 s
Message Out in request mode 1.0.8timeoutMs, default 5 s, held between 100 ms and 60 s

A node that exceeds its timeout fails, which is a failure like any other: the branch stops unless the node's error output is wired, and a Catch reports it either way. Set timeouts shorter than the caller's patience — an HTTP client that gave up long ago does not benefit from a node still running.

Errors​

By default a failing node stops its branch: the error is recorded against the execution, the other branches carry on, and the pipeline stays running for the next trigger.

That default is the right one for a fault nobody planned for. For the ones you did plan for, there are two features, and they answer different questions.

Catch nodeError output port
AnswersTell somebody this brokeCarry on without it
ShapeA separate node, no input, dispatched after a failureA second socket on the node that failed
ScopeEvery node in the pipeline, or a chosen fewThat one node
The failed branchCannot be resumed — the handler is a new branchContinues, down the error wire
EnabledBy adding the nodePer node, on the Resilience (Retry) tab

They compose. A pipeline can report every failure through one Catch and recover from a specific one in flow.

The error output port New in 1.0.4​

Open a node's property panel, go to Resilience (Retry), and switch Error Output on. A second socket appears on the node, drawn in red. It fires when that node has finally failed — after its retries are exhausted, not on each attempt.

┌─ out ──────────────────────────┐
Inject → fetch-price ──┤ ├→ compute → write-db
└─ error → Python (cached value) ┘

Wiring the error branch back into compute runs compute once, with whichever edge delivered — the same convergence rule that governs any other node with several inbound wires. That is the whole point of the port: recovery without duplicating the rest of the pipeline underneath a handler.

The message on the error wire is the same envelope a Catch emits — error, source and the input that caused the failure.

Four behaviours worth knowing:

  • The node reports WARNING, not ERROR. It draws amber on the canvas and stays in the run log, because a handled failure is still a failure — but it is no longer an outage, and the branch it feeds is allowed to run.
  • A routed error does not also fire a Catch. You wired the failure somewhere, so it went there.
  • An error output switched on but left unwired fails normally. Routing an error into empty space would swallow it, which is worse than the behaviour it replaces.
  • Switch has no error output. A router publishes its own ports; the two are not combined.

What a failure looks like in the log​

LevelMeans
ERRORThe node failed and nothing handled it. The branch stopped
WARN 1.0.4Something went wrong and was handled — a node whose failure left through its error output, or another recoverable fault
RETRYINGAn attempt failed and another one is coming

WARN is filterable in the system log toolbar, which is the point of it: a handled fault is neither routine chatter nor an outage, and it used to be recorded as one or the other.

A node on a disabled connection fails Changed in 1.0.7​

Switching a connection's Enabled toggle off now stops the pipeline nodes that use it — SQL Query, MongoDB, QuestDB, Send Email, Telegram and WhatsApp. The node fails, with an error naming the connection and the toggle, so disabled is distinguishable from not found.

Before 1.0.7 the toggle reached only the data path. A pipeline node went on resolving the connection as though nothing had changed, and the notification senders — which hold no pool and build each send fresh — were the sharpest case: a disabled SMTP connection went on sending mail. Failing loudly is deliberate. A pipeline that quietly stops notifying is worse than one that says why, and the failure goes wherever your Catch or error output sends it.

The Test and Browse actions on the connection still work while it is disabled — you configure and test a connection before you switch it on.

Writes​

Failures on the way out to a device or a database are covered separately by store-and-forward: transport failures buffer and retry, data errors quarantine.

Debugging​

1. Attach a Debug node. The fastest way to see what a node actually produced, in the Debug panel.

2. Trigger a single node.

Use Trigger node on the node itself (needs Execute Pipeline). It runs one node with its current input, without running the whole graph — the pipeline equivalent of stepping.

3. Read the execution log.

Executions, individual executions and per-node results all require View Execution Logs.

4. Watch node status on the canvas. Nodes show live state as messages pass through, pushed over the telemetry bus.

5. Lint Python before running. The editor lints as you type, so syntax errors surface while typing rather than at 03:00.

Performance​

SymptomCauseFix
Pipeline lags behind its triggerThe graph takes longer than the intervalLengthen the interval, or split the work across pipelines
High CPU on the Python workerPer-message Python for high-rate dataFilter with RBE first; move set-based work into SQL
Database saturatedOne write per messageBatch with Join, or aggregate before writing
Memory growthVery large arrays held in memoryUse Array Iterator to stream instead of materialising
Slow tag readsA loop of single readsUse one multi-tag read (readAll)

Two rules cover most cases: filter early (drop what you do not need at the first opportunity) and batch late (combine before the expensive downstream step).

Concurrency​

  • Executions of the same pipeline can overlap if the trigger fires faster than the graph completes. Design nodes to be re-entrant, or lengthen the interval.
  • Batch Transform processes items in parallel; ordering across items is not guaranteed.
  • Variables are shared across pipelines. Use system.vars.incr for counters — it is atomic; read-modify-write is not. → Variables

Starting and stopping​

Starting and stopping a pipeline — individually or all of them in the project — requires Start/Stop Pipeline. Executing once requires Execute Pipeline.

Disabling a project stops its pipelines. Disabling a pipeline keeps it out of "start all" — the right way to shelve one without deleting it.

Stopping a pipeline resets the traffic counts of the Telegram bots it was using — the 12 in · 5 out under its nodes — so a restart counts the run you are watching rather than every run since the gateway started. Changed in 1.0.7 A bot that another running pipeline still uses keeps its counts: that pipeline is still incrementing them, and zeroing them would read as "nothing has happened" about something happening right now. Only the counts reset — the last error and any back-off describe the link, not the run, and are often exactly what somebody is reading when they press Stop.

Next​

→ Variables