Asynchronous execution
flowable:async is the CMMN attribute most often misread, in a way that produces models built on a false expectation. It appears in 41 of the 968 corpus documents.
What “async” does not mean
Section titled “What “async” does not mean”Async controls transaction boundaries, not execution order.
Setting flowable:async="true" on a plan item does not make it run in parallel with its siblings. It does not make the case concurrent. It does not speed anything up by overlapping work.
A case instance remains sequential. One thing happens at a time, in the order the plan and its sentries dictate. Async changes where the engine commits, not what runs next.
What it does mean
Section titled “What it does mean”Async splits the work of activating or leaving a plan item across two transactions instead of one:
- Async-before (
flowable:async) — the engine commits the state it has, then picks the plan item up in a fresh transaction to start it. - Async-leave (
flowable:asyncLeave) — the engine commits the plan item’s completion, then continues the case in a fresh transaction.
Why you would want that:
- A shorter transaction. Long-running work does not hold a database transaction open across it.
- A retry boundary. If the work fails, the retry starts from the committed point rather than replaying everything since the case last committed.
- A failure boundary. An error after the commit cannot roll back what came before it.
Exclusive jobs
Section titled “Exclusive jobs”In Flowable, async jobs default to exclusive, meaning at most one job for a given case instance runs at a time. That default is what keeps a case sequential even once its steps are separate jobs — turning it off is what would allow genuine concurrency within one case, with all the interleaving hazards that implies.
The important consequence: the default async configuration does not give you parallelism. If you set async expecting speed, you get transaction boundaries and no speed.
Orvanta refuses async today
Section titled “Orvanta refuses async today”flowable:async and flowable:asyncLeave are refused at deploy, with the element id and the attribute named.
The reason is exact: a transaction boundary needs a transaction to bound, and it has to be the one the model asked for. Orvanta’s CMMN engine is a pure, I/O-free library — no database, no clock, no network, by construction — and the transaction lives entirely outside it, in the worker that commits one quiescence pass. flowable:async asks for a boundary at this plan item, which is not a unit that exists on Orvanta’s side of the line (see Orvanta’s engine and quiescence). Accepting async and ignoring it would silently give the model a different failure and retry profile from the one its author asked for, which is precisely the class of bug the refusal position exists to prevent.
33 of 967 corpus documents are blocked at deploy on this attribute.
Two lifecycle states and two transitions are consequently modelled but unreachable: the states async-active and async-active-leave, and the transitions async-activate and async-leave-active.
What this changes about a model you are porting
Section titled “What this changes about a model you are porting”If you are bringing a case model over from Flowable and it uses async:
- It will not deploy. The refusal names the element and the attribute.
- Removing the attribute does not change what the model does — only its transaction and retry granularity. The plan, the sentries and the completion rules all behave identically without it.
- You lose the retry boundary. Once Orvanta has a worker, an async-before step would resume from its own commit point; without it, a failure resumes from wherever the case last committed.
For a model where async was set out of a mistaken belief that it produced parallelism — which is common — removing it costs nothing at all.
Orvanta’s engine and quiescence
Section titled “Orvanta’s engine and quiescence”This is the part to internalise if you are porting a model that leans on async. Orvanta’s CMMN engine does not step one transition at a time and hand control back. It runs to quiescence: it keeps evaluating criteria and firing transitions until nothing further can happen without an external trigger, then returns the whole resulting state and the events that got there.
That is a different shape from Flowable’s job-row model, where each async step is a row in a job table. It means the natural transaction boundary for Orvanta is “one quiescence pass”, and it is why the async attribute cannot simply be mapped across — the unit it bounds does not exist in the same form.
The pass is bounded at 10,000 evaluation cycles. See Repetition for why that bound is there.
See also
Section titled “See also”- Supported CMMN elements — every refusal in one table.
- Coming from Flowable — the other gaps worth knowing before you port.