Execution modes
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 status | Meaning |
|---|---|
pending | The save landed; the build has not started yet. |
building | The bundle is being compiled. |
ready | The bundle exists and the workflow can run. |
failed | The 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 trigger firing that was refused this way is not lost: it lands under Missed runs, where you can replay it from the payload captured when the trigger fired.
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_mode | Effect |
|---|---|
async_only | Default. The run is started and the caller gets an acknowledgement immediately. Asking for a synchronous run is refused. |
sync_only | The caller always waits for the result. Asking for an asynchronous run is refused. |
caller_decides | Either 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.
Synchronous runs are capped at 30 seconds
A synchronous run holds the caller until the workflow finishes, and exceeds-30-seconds is a gateway timeout. The run itself is not cancelled by that — it keeps going and lands in the run history with its real outcome — but the caller has already been answered with a 504, so it 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
| Situation | Mode |
|---|---|
| A file pipeline, an ERP sync, anything on a schedule | async_only — nobody is waiting |
| A caller that needs the result of the work in its response | sync_only, and keep the workflow short |
| One workflow serving both a waiting caller and an unattended schedule | caller_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.
Where to go next
- The workflow document — the graph all of this executes, and what a save does.
- Triggers — the four ways a run starts.
- Failure handling — retries, error routing and timeouts, per node.
- Runs — what a finished run leaves behind.