Skip to main content
Version: 1.0.4

Variables

Variables are a shared key/value store available to every pipeline and script in the gateway. They hold the state that does not belong to a tag and does not deserve a database table: a counter, a last-run timestamp, a feature flag, a cached token.

Storage modes

ModeSurvives restartUse for
PersistentYesCounters, last-processed markers, configuration flags
VolatileNoCaches, in-flight state, anything cheap to recompute

The workspace has a default mode; individual variables can override it at write time.

ActionPermission
List variables and read the default modeauthenticated
Change the default storage modeConfigure variable storage
Delete a variableEdit pipelines

Using variables

Python
last = system.vars.get("last_export_ts", 0)
rows = system.db.runQuery(
"SELECT * FROM events WHERE ts > ?", [last], "ReportingDB"
)
if rows:
system.vars.set("last_export_ts", rows[-1]["ts"], "persistent")

count = system.vars.incr("exports_today") # atomic
JavaScript
const last = await system.vars.get("last_export_ts", 0);
await system.vars.set("last_export_ts", Date.now(), "persistent");
const count = await system.vars.incr("exports_today");

API

CallReturns
get(name, defaultValue?)The value, or defaultValue when unset
set(name, value, storage?)true. storage omitted ⇒ workspace default
delete(name)true
keys()Every variable name
incr(name, by?)The new value after atomically adding by (default 1)
list()Every variable with value, type, storage and last-updated time

Use incr for counters

# ❌ race: two pipelines can read the same value and both write n+1
n = system.vars.get("count", 0)
system.vars.set("count", n + 1)

# ✅ atomic
n = system.vars.incr("count")

Variables are shared across concurrently executing pipelines. Read-modify-write loses updates; incr does not.

Patterns

Incremental extract

last = system.vars.get("etl_watermark", "1970-01-01T00:00:00Z")
rows = system.db.runNamedQuery("changes_since", {"since": last})
# ... process ...
if rows:
system.vars.set("etl_watermark", rows[-1]["updated_at"], "persistent")

Restart-safe: the watermark is persistent, so a restart resumes rather than reprocessing.

Run-once-per-period guard

import datetime
today = datetime.date.today().isoformat()
if system.vars.get("daily_report_date") == today:
return None # already ran
# ... produce the report ...
system.vars.set("daily_report_date", today, "persistent")

Cached credential

token = system.vars.get("api_token")
if not token:
token = fetch_token()
system.vars.set("api_token", token, "volatile") # not written to disk

Variables, tags or a database?

NeedUse
A process value with quality, history, alarmsA tag (internal tag if QUBIQ owns it)
Coordination state between pipelinesA variable
Something an operator should see or change on a screenAn internal tag — variables are not bindable
Anything queried, reported on or retained long-termA database

A variable is deliberately invisible to the visualization layer. If a value belongs on a screen, it belongs in a tag.

Cautions

  • Not encrypted. Do not store credentials you would not want an operator with script access to read. Use a connection's credential storage instead.
  • Not audited per write. Variable changes are not in the security audit journal.
  • Not namespaced. One flat name space per gateway — prefix by concern (etl_watermark, report_lastrun) so unrelated pipelines do not collide.
  • Volatile means volatile. A restart clears it, including a supervisor-initiated service restart.

Next

REST endpoints