Execution modes

What has to be true before a workflow can run, the execution_mode policy and its per-request override, the 30-second synchronous cap, and which entry point defaults to which mode.

Everything in Integration Studio runs on one durable execution engine. A workflow's steps are executed one at a time against the graph you saved, each step's result is recorded, and a step that fails is retried according to its own policy. There is no second engine and no separate in-process fast path: a synchronous run and an asynchronous run execute the same workflow the same way — the only difference is whether the caller waits for the result.

This page covers what has to be true before a run can start, and how the mode is decided.

A workflow only runs when its build is ready

Saving a workflow does not make it runnable. Each save bumps the workflow's revision and queues a build that compiles the graph into an executable bundle. The build state is one of:

Build statusMeaning
pendingThe save landed; the build has not started yet.
buildingThe bundle is being compiled.
readyThe bundle exists and the workflow can run.
failedThe build failed. Fix the workflow and save again to re-queue it.

A run is rejected while the build status is anything other than ready. That applies to every path into a run — a manual start, a schedule firing, an inbound webhook call, an event. Cockpit shows the build state on the workflow, and starting a run from the editor while a build is in flight holds the request and starts it once the bundle is ready rather than failing.

Build state does not currently refresh by itself in the workflows list — a workflow that has finished building keeps reading pending until you reload the page.

A schedule firing or event that was refused this way is not lost: it lands under Missed runs, where you can replay it (an event keeps the payload captured when it fired, a schedule keeps none). A webhook call is refused with a 409 instead, so the caller has to send it again.

Execution mode is a workflow-level policy

Every workflow carries an execution_mode. It is a policy about who may decide whether a caller waits, not a choice of engine:

execution_modeEffect
async_onlyDefault. The run is started and the caller gets an acknowledgement immediately. Asking for a synchronous run is refused.
sync_onlyThe caller always waits for the result. Asking for an asynchronous run is refused.
caller_decidesEither is allowed; the caller may override per request.

Under caller_decides, the two entry points default differently, and this catches people out:

  • A webhook call defaults to synchronous — the caller waits for the result, because a caller that bothered to make an HTTP request usually wants the answer.
  • Creating a run directly defaults to asynchronous — start it and walk away.

If a request asks for a mode the policy forbids, the request is refused before any run record is created. Nothing is left half-started.

You set the execution mode when you create the workflow. When you test a workflow from the canvas, the modes offered are the ones its execution_mode allows — one if it is pinned, both if the caller may choose.

Nothing stops two runs overlapping

A workflow has no concurrency setting: no lock, no "skip if already running", no limit on parallel runs (as of 2026-09). Two triggers close together start two runs, and a schedule can fire twice. Design for it — make every write idempotent, so a second run finds the work already done, or have the workflow check for a run in progress before it starts writing.

Synchronous runs are capped at 30 seconds

A synchronous run holds the caller until the workflow finishes. After 30 seconds Integration Studio stops waiting and answers 504 with "message": "Workflow execution timed out.". That 504 comes from Integration Studio itself, not the API gateway, which never sends one (see Errors). The run itself is not cancelled by that — it keeps going and lands in the run history with its real outcome — so the caller must not treat the timeout as "did not happen".

Two consequences worth designing around:

  • Anything that lists a directory, walks a large file, or waits on a batch job in an external system does not belong on a synchronous path. Put it on a schedule or on an asynchronous webhook.
  • If a caller retries after a timeout, the workflow runs twice. Make workflows that write data idempotent — key the write on something stable from the payload rather than on the fact of the run.

Choosing a mode

SituationMode
A file pipeline, an ERP sync, anything on a scheduleasync_only — nobody is waiting
A caller that needs the result of the work in its responsesync_only, and keep the workflow short
One workflow serving both a waiting caller and an unattended schedulecaller_decides, and remember the webhook default

If in doubt, leave it asynchronous. A caller can poll or be notified; a caller that has been sitting on an open connection for 29 seconds cannot be rescued.

Integration Studio is a Cockpit surface, and Cockpit is where workflows, triggers, runs and credentials are normally managed. They can also be driven from your own code: the Integration Studio API covers workflows, triggers, runs, revisions, credentials and tenant secrets, authenticated with the token of a signed-in person and acting on one tenant — and reachable by an AI assistant on the same token, which is what What an AI agent can change is about. Where you want automation over the platform's data rather than over the studio, that is the revenexx API — see Reaching Revenue Cloud.

Where to go next

Was this page helpful?