Understanding Workflows

Flows are the automation engine of Vesbite. They connect device events to business logic and external services, running in the cloud without manual intervention. This document explains how Flows work, why they are designed the way they are, and how the execution model keeps your automations reliable.

What is a Flow?

A Flow is a visual automation defined on a canvas. It starts with a trigger (something that initiates execution) and contains one or more actions (operations that do work). Triggers and actions are connected by edges that define the order of execution.

When a trigger fires, the Flow engine creates an instance – a single, trackable run of the Flow – and begins executing actions in order, following the connections you defined.

Each Flow instance is independent. If a device event fires 100 times, 100 separate instances execute concurrently, each with its own data and state.

The Flow Canvas

The Flow builder presents your automation as a directed acyclic graph (DAG) – a set of nodes connected by edges that flow in one direction without loops.

Nodes are the boxes on the canvas. Each node is either a trigger or an action. Nodes have handles – connection points on their edges where you attach wires.

Edges are the lines between nodes. An edge means “when this node finishes, execute that node next.” Edges connect from an output handle on one node to the input handle on another.

Handles come in two varieties:

  • Output handles – the default output (success) and optionally an error handle for failure paths
  • Input handles – where incoming edges connect

A node can have multiple output handles. For example, a Branch node has one output for the “true” path and another for the “false” path. This is how Flows support conditional logic and parallel paths.

Triggers: Why Flows Need Them

Every Flow must have exactly one trigger. The trigger answers a fundamental question: when should this automation run?

Without a trigger, a Flow is just a definition sitting idle. The trigger is what brings it to life.

Device Event Trigger

The most common trigger type. A Device Event trigger fires every time a specific device publishes a matching event. For example: “whenever my RFID reader publishes a tagRead event, start this Flow.”

The event payload becomes available as workflow data, so subsequent actions can reference values like {{ variables.epc }} or {{ variables.rssi }}.

Timer Trigger

Fires once after a specified delay. Useful for scheduled, one-off operations like “run this cleanup task 24 hours from now.”

Cron Trigger

Fires on a recurring schedule defined by a cron expression. Examples: every 5 minutes, daily at 9 AM, the first Monday of each month. Use this for periodic tasks like polling an API, generating reports, or sending digests.

Manual Trigger

Fires when a user explicitly clicks “Run” in the dashboard. Useful for testing, one-time operations, or admin tasks that should not run automatically.

Each trigger type populates the workflow context with relevant data. A Device Event trigger provides the event payload. A Cron trigger provides the scheduled time. This data is available to all subsequent actions through expressions.

Actions: The Work Units

Actions are the nodes that perform operations in your Flow. Each action takes inputs (which can be literal values or expressions), does something, and optionally produces an output that downstream nodes can reference.

Device Actions

Send commands to devices: start scanning, stop scanning, print a label. Device actions use a request/reply pattern, so your Flow receives the device’s response and can branch on success or failure.

Integration Actions

Interact with third-party services: create an Airtable record, send a SendGrid email, make an HTTP request, query a database. Integration actions handle authentication automatically using stored credentials.

Logic Actions

Control the flow of execution:

  • Branch – evaluate a condition and take one of two paths
  • Set Variable – store a value for use by later nodes
  • Delay – pause execution for a specified duration

Data Actions

Transform and manipulate data:

  • HTTP Request – call any API and capture the response
  • Log – write a message to the instance log for debugging

Each action type defines its own inputs and outputs. The Flow builder knows these definitions (from the action’s schema) and presents appropriate configuration fields in the node’s properties panel.

Connections and Handles

Connections define execution order. When you draw a line from Node A’s output handle to Node B’s input handle, you are saying: “after A finishes, run B.”

Branching

A single node can have multiple output handles, each leading to a different downstream path. The Branch action is the clearest example – it evaluates a boolean condition and routes execution to either the “true” or “false” handle.

But branching is not limited to Branch nodes. Any node’s output can connect to multiple downstream nodes, creating parallel execution paths.

Converging

Multiple paths can converge on a single node. If Node C has incoming edges from both Node A and Node B, it will execute once when all its predecessors have completed.

Error Handles

Most action nodes have a secondary error handle in addition to their default output handle. If the action fails (an HTTP request times out, a device is offline, an expression is invalid), execution flows through the error handle instead of the success handle.

This lets you build explicit error-handling paths:

[HTTP Request] ──success──> [Log Success]

    error

      v
[Send Alert Email]

If you do not connect the error handle, a failed action causes the entire Flow instance to enter the Failed state.

The Execution Model

Flows execute in the cloud using a state machine. Understanding this model helps you reason about what happens when things go wrong or take a long time.

Instance States

Each Flow instance moves through a defined set of states:

StateMeaning
PendingThe instance has been created but not yet started
ArmedThe instance is waiting for its trigger to fire
RunningThe instance is actively executing actions
SuspendedThe instance is paused, waiting for an external event (e.g., an Await Device Event action)
CompletedAll actions finished successfully
FailedAn unhandled error occurred during execution
CancelledA user manually stopped the instance

The typical happy path is: Pending -> Armed -> Running -> Completed.

Durability

Flow instances are durable – their state is persisted at each step. If the server restarts while an instance is running or suspended, the instance resumes from its last saved state. You do not lose progress.

This is critical for long-running Flows that might wait hours or days for a device event before continuing.

Concurrency

Every trigger event creates a new, independent instance. If your RFID reader fires 50 tag reads in a second, 50 Flow instances execute concurrently. They share nothing – each has its own variables, its own execution path, and its own state.

Suspension

Some actions pause execution and wait for something external. The most common example is Await Device Event: the Flow suspends until a specific device event arrives, then resumes with the new event data.

While suspended, the instance consumes no resources. It is simply a record in the database waiting to be woken up.

Draft vs. Published

Flows have two lifecycle phases: Draft and Published.

Why this distinction exists

Editing a live automation is dangerous. If you change a Flow while instances are running, you could introduce inconsistencies – some instances running the old definition, others running the new one, and no way to tell which is which.

The Draft/Published model solves this:

  • Draft is your working copy. Edit it freely. Test it with the Manual trigger. Nothing happens in production until you publish.
  • Published is the active version. It is immutable – once published, it cannot be edited. Triggers are only active on the published version.

When you publish a new version, the old published version is deactivated. Any currently-running instances of the old version complete with the old definition (they are not interrupted). New trigger events create instances of the new version.

This gives you a safe workflow: edit, test, publish, repeat.

Error Handling

Errors are inevitable – devices go offline, APIs return 500s, expressions reference missing variables. Vesbite gives you tools to handle them gracefully.

Error Handles on Nodes

As described above, each action node has an error output handle. Connect it to define what should happen when that specific action fails. This is the primary mechanism for granular error handling.

Unhandled Errors

If an action fails and its error handle is not connected, the Flow instance transitions to the Failed state. The error details (message, stack trace, which node failed) are recorded in the instance log for debugging.

Designing for Failure

Best practices:

  • Connect error handles on any action that calls an external service (HTTP requests, integrations, device actions)
  • Use a Log action on error paths so you can diagnose failures later
  • Consider sending notifications (email, webhook) on critical failures
  • Keep Flows focused – a single-purpose Flow is easier to debug than one that does everything

Variables and Data Flow

Data moves through a Flow via variables and node outputs. Understanding how data flows between nodes is essential to building effective automations.

Workflow Variables

Variables are named values that persist for the lifetime of a Flow instance. They are stored in a shared context that all nodes can read and write.

Variables are populated by:

  • Triggers – a Device Event trigger sets variables from the event payload (e.g., variables.epc, variables.rssi)
  • Set Variable actions – explicitly store a computed value under a name you choose
  • Some actions – certain actions automatically set variables as a side effect

Node Outputs

Every action can produce an output – a structured result that downstream nodes can reference. Outputs are accessed by the node’s activity ID:

{{ output("http-request-1").statusCode }}
{{ output("airtable-create").id }}

Outputs are ephemeral within the instance – they exist for as long as the instance is running and can be referenced by any downstream node.

Expressions as Glue

Expressions are how you wire data between nodes. Instead of hard-coding values in action inputs, you write expressions that reference variables and outputs:

Record EPC: {{ variables.epc }}
Read strength: {{ variables.rssi }}
Lookup result: {{ output("db-query").rows[0].name }}

Expressions are evaluated at runtime, in the context of the current instance. This means the same Flow definition can process thousands of different events, each with its own data.

Learn more about expressions -->

Next Steps