Flowable event subprocesses for handling events anywhere in a process scope
An event subprocess in Flowable is a subprocess that has no incoming or outgoing sequence flow and instead starts when a specific event occurs anywhere inside the scope that contains it. Teams need one when a long-running process must react to a cancellation, an escalation, a status request or an error at any step, and attaching a handler to each activity would multiply the model and make it fragile. The trigger can be an error, message, signal or timer start, and the subprocess can either interrupt the work already in progress or run alongside it. Before you model one, list every event your business owners expect to arrive mid-process and decide, for each, whether the current work should stop.
The difference from a boundary event is scope. A boundary event is attached to one activity and only fires while that activity is active, so a cancellation request that can arrive during any of twenty steps needs twenty boundary events. An event subprocess sits at the process or subprocess level and covers everything beneath it, which keeps the handling in one place. Confirm the exact BPMN rules for interrupting and non-interrupting starts against the Flowable advanced documentation and the Flowable version you run, because behavior around nested scopes and variable visibility is where models most often surprise their authors.
DeployOpen plans and builds these models inside your own infrastructure, with the event catalog, interruption decisions and status-request responses agreed before modeling starts. The work also covers testing each trigger against the process states it can meet, including cancellation during a call activity or while a timer is pending. Ask any partner to show how interrupting cancellation releases open user tasks, pending timers and called processes, and how a status request reads state without altering it. Those answers determine the effort far more than the number of event subprocesses drawn.
Which start event fits each trigger
An error start event on an event subprocess fires when a BPMN error is thrown inside the scope that contains it. It is the natural fit when a failure in a step should move the process to a defined recovery path, such as notifying an operator, recording a compensating status or routing to a manual review queue, instead of ending in a technical failure. The error must be raised by an activity in scope, so the team has to agree on how service tasks map Java exceptions to BPMN error codes.
- What starts it: a BPMN error thrown within the enclosing scope, optionally filtered by error code.
- Typical situation: a payment or booking call returns a business rejection that the process must handle, not retry.
- Scope check: confirm which activities can raise the error and whether the error code is matched or catches all errors.
- Failure distinction: confirm how technical exceptions that are not mapped to a BPMN error behave, since they follow job retry handling instead.
- Ownership: confirm who maintains the list of error codes shared between developers and process designers.
Before you design the recovery path, check the Flowable docs for how error handling interacts with the transaction in which the error is thrown.
A message start on an event subprocess waits for a named message to arrive while the enclosing process instance is running. It fits situations where an outside party, such as a customer, a partner system or an internal team, needs to interrupt or add work to an in-flight case, for example a cancellation request or an update to a shipment address. Correlation decides which running instance receives the message, so this is where most defects appear.
- What starts it: a message with a matching name delivered to a running instance in the same scope.
- Typical situation: a customer requests cancellation of an order that is already being fulfilled.
- Correlation check: confirm how the message is correlated to the instance, whether by business key, variables or another identifier, in the Flowable docs for your engine version.
- Delivery path: confirm whether messages arrive through the API, a broker adapter or the event registry, since each has its own behavior.
- Duplicates: confirm how the design handles a message that arrives twice or after the scope has already ended.
Write down the correlation key for each message name before any diagram is drawn.
A signal start event on an event subprocess reacts to a broadcast signal. Signals are not addressed to one instance, so they suit company-wide announcements that several running processes must react to at once, such as a policy change, a regulatory calendar update or a system freeze. The main risk is unintended reach: a signal can affect every subscribed instance in its scope, which may be wider than the team expects.
- What starts it: a signal with a matching name, received by every eligible instance in the signal's scope.
- Typical situation: an operations team needs all open onboarding cases to pause during a planned outage.
- Scope check: confirm whether signals are scoped to the engine, to a tenant or to the process definition, and how that affects delivery.
- Tenant handling: confirm how signal names and tenants interact if you run multi-tenant deployments.
- Blast radius: confirm which definitions subscribe to each signal name and document that list.
Review the signal catalog with the people who can send signals, because a single broadcast can reach processes owned by other teams.
A timer start event on an event subprocess fires after a duration or at a scheduled point while its enclosing scope is active. It is used for deadlines and reminders inside a process, such as escalating an approval that has waited too long. Timers are executed by the async executor, so their accuracy depends on job execution, not only on the schedule written in the model.
- What starts it: the expiry of a configured timer while the enclosing scope is still running.
- Typical situation: a loan application must be escalated if no underwriter has acted within a set period.
- Expression check: confirm the duration or date format the Flowable docs accept for your engine version, and how time zones are interpreted.
- Executor dependency: confirm how the async executor is configured in your deployment, since timers fire through it.
- Interruption: confirm whether the timer interrupts the enclosing scope or runs alongside it.
Test each timer with a realistic clock setting in a non-production environment before relying on it for a business deadline.
How interrupting and non-interrupting event subprocesses change the main flow
An interrupting event subprocess cancels the activities running in the parent scope when its start event fires, and the main flow continues only through the event subprocess. A non-interrupting event subprocess leaves those activities running, so the parent scope keeps its tokens and the event subprocess runs alongside them. That difference is the first design decision for each trigger. An error or cancellation-style reaction usually needs interruption so that work stops. A reminder, a status lookup or an audit step usually needs the main flow to keep moving. Confirm the exact semantics for interruption, token handling and the handling of child executions in the Flowable version you run, since the BPMN docs describe the general rule and the engine's behavior is what your tests will exercise. The Flowable docs cover the async executor, which also matters when timers fire against running work.
A status request is the clearest case where the choice matters. If the request is modeled as an interrupting path, a simple question from a manager can cancel a pending approval or a payment step, which is rarely what the business wants. A non-interrupting event subprocess that only reads process variables and writes a response, without moving tokens or calling services that change state, keeps the main flow intact. Decide explicitly whether a status request may pause work (for example, by waiting on a lock or a human decision) or must only read it. Write that rule into the model review checklist, because a diagram rarely shows which variables a delegate touches.
Test both paths separately. For interrupting handlers, verify that every activity in the parent scope is cancelled, that boundary timers and external subscriptions are removed, and that the process reaches the intended end state. For non-interrupting handlers, verify that the main flow still completes, that the event subprocess can run more than once when the trigger repeats, and that variables written by the handler do not overwrite values the main flow changes. Your tests should also cover the case where the trigger arrives while the parent scope is inside a transaction boundary or waiting on an async job. Plan the test fixtures and the event timing as part of the build, not as a last step before go-live.
Configuration options and when each one fits
This table compares the event subprocess options Flowable offers for handling events inside a process scope, from the trigger type to interrupting behavior and placement. Read each row as a design decision: the trigger tells the engine what starts the handler, and the interrupting setting decides whether the main flow survives. Confirm each option against the Flowable BPMN documentation for your engine version before you commit the model.
| Option | What it does | Typical use | Trade-off |
|---|---|---|---|
| Error start event | Starts an event subprocess when a BPMN error is thrown inside its scope | Converting a known business failure into a compensating path | Only catches errors that the delegates or activities in scope actually raise |
| Message start event | Starts the handler when a correlated message arrives while the scope is active | Accepting a cancellation or an update from another system | Needs a correlation key and a way to route messages to the right instance |
| Signal start event | Starts the handler when a broadcast signal is thrown in the matching scope | Notifying many running instances of one shared change | Signals reach every subscriber, so unintended instances may react |
| Timer start event | Starts the handler when a timer fires while the enclosing scope is active | Reminders, deadlines or time-boxed escalations inside a long process | Timer firing depends on the async executor, so timing is approximate |
| Interrupting | Cancels the main flow in the scope once the event subprocess starts | Cancellation, abort or a hard deadline that must stop the work | Discards in-flight work in the scope, so compensation or cleanup must be designed |
| Non-interrupting | Runs the handler alongside the main flow without stopping it | Status requests, notifications or partial updates during normal work | Both paths can run at once, which needs guards against conflicting changes |
| Scope placement | Sets which subprocess or process level can trigger the handler | Limiting a handler to one phase of work rather than the whole instance | Wider scope is simpler to model but harder to reason about when it fires |
Patterns for cancellation and status requests
Event subprocesses let a running Flowable process react to cancellations, status queries, timeouts, failures and privileged intervention without rewriting the main path. Each pattern below changes state in a different way, so each one can leave tokens, variables or external work inconsistent if it is wired carelessly. Test every pattern against the instance states it can interrupt, not only the happy path.
Cancellation with compensation hand-off
A cancel message starts an interrupting event subprocess that stops the main flow and hands completed steps to compensation handlers. The risk is that a cancel arrives while a service task is mid-call, so an external system is charged or booked but the compensation never runs. Check that every completed activity with an external effect has a compensation handler, that compensation runs once, and that the cancel is idempotent when repeated.
Status request without state change
A non-interrupting event subprocess triggered by a message reads process variables and returns them to the caller while the main flow keeps running. The risk is an accidental write: a script or expression that sets a variable, or a task listener that fires, moves the process forward or alters data that other steps depend on. Test that the status path leaves variables, tokens and task assignments unchanged, and that concurrent status requests do not block the main flow.
Escalation on timer
A timer inside an event subprocess escalates work that has stalled, such as an approval waiting beyond its service window, by reassigning it or notifying a manager. The risk is that a non-interrupting timer fires repeatedly on a long-running instance, creating duplicate escalations, or that an interrupting timer discards work that was almost complete. Test the cycle configuration, the reassignment logic and what happens when the task completes just before the timer fires.
Error handling that routes to clean-up
An error event subprocess catches a BPMN error thrown from a delegate and routes the instance to a clean-up path that releases locks, closes external tickets and records the failure. The risk is that the clean-up path itself calls a failing system, leaving the instance stuck in a state that neither the main flow nor the error path can finish. Check which errors map to this path, that the clean-up steps are safe to repeat, and that an instance can still reach an end event afterward.
Manual override by a privileged user
A message start or intermediate catch on an event subprocess lets an authorized operator force an instance to a specific outcome, such as approving a stalled request or closing it. The risk is an override that skips the authorization and audit steps the normal path enforces, so the record shows an outcome no approver made. Verify that the engine does not check authorization for you, that your application checks the operator's role, and that each override writes a reason and actor to history.
How to set up event subprocesses in a Flowable model
This sequence takes an event subprocess from a confirmed engine version to a tested model in which each trigger path has been exercised and its state recorded. The output is a deployed definition, a verification record and a set of correlation and variable rules your team can maintain.
Confirm engine version and deployment model
Before modeling, record the Flowable engine version, the engine type you need (BPMN for event subprocesses) and how the engine will run: embedded as a JAR in a Java application, inside a Spring application through the Spring Boot starters, or over HTTP through the REST application. Check the configuration and Spring Boot documentation for the supported database and framework baseline for that version. The step is done when the team has a short written record of these choices and has confirmed them against the Flowable docs. Ask DeployOpen or your Flowable contact to confirm any version-specific behavior you depend on.
Model the parent scope and its activities
Draw the main process or subprocess that the event subprocess will attach to, including its user tasks, service tasks and any wait states. Name each activity clearly, because event subprocess behavior is defined relative to the scope that contains it. Identify which activities must stop when an event fires and which must keep running. The step is done when a reviewer can point to the scope boundary and list the activities inside it, and when the model deploys without validation errors in a local engine.
Add event subprocesses with the chosen triggers
Inside the parent scope, add one event subprocess for each trigger the requirement needs: error, message, signal or timer start events. Set each event subprocess to interrupting or non-interrupting according to whether the parent work should stop. Keep cancellation and status request paths in separate event subprocesses so each has one clear purpose. The step is done when every trigger is visible on the diagram with its interrupting setting recorded, and the model still deploys cleanly.
Define variables and correlation keys
Decide which process variables the event subprocess reads and writes, and which business key or correlation value identifies the right instance when an external message or signal arrives. Document the variable names, types and the owner of each value. Confirm with the team that message correlation uses a value that is unique within the expected scope and tenant. The step is done when a written table lists each trigger with its correlation key, required variables and expected state change, and the table has been reviewed by the people who send the events.
Deploy the model to a test environment
Deploy the process definition to a test environment that matches production in engine version, database type and identity setup. Confirm the deployment created a new definition version and that the previous version is still available for running instances. Check the deployment log for warnings about unresolved expressions or missing listeners. The step is done when the deployed definition ID and version are recorded and the engine starts without errors.
Trigger and verify each event path
Start a test instance and fire each trigger in turn: throw the error, send the message, broadcast the signal, or wait for the timer. After each trigger, check the process instance state, the active activities and the variables, and confirm that the parent work stopped or continued as designed. Compare these results with the history records for the same instance. The step is done when every path in the design has a recorded test result, and any mismatch has been logged as a defect with the trigger and the observed state.
Confirm cancellation and status request behavior
Test the cancellation path and the status request path as separate scenarios. For cancellation, confirm that the parent scope exits, that compensation or cleanup activities run if they were modeled, and that the instance ends in the expected state. For status requests, confirm that a non-interrupting path returns the requested information without disturbing the main work. The step is done when both scenarios pass in the test environment and the results are attached to the change record for review.
Security and operational considerations for event subprocesses
Event subprocesses can be triggered from outside the process, so who can send messages and signals, how cancellation is authorized, and how timers fire across nodes all shape the risk. The cards below cover the decisions and checks that connect those areas for Flowable event subprocesses.
Who can trigger event subprocesses
Message and signal events reach a running process through the Java and REST APIs, so any caller with access to those interfaces can trigger a waiting event subprocess. Map every application or service account that can send messages or signals, and confirm which events are reachable from outside the platform. Check that the event names you expose are not guessable and that no generic endpoint lets a caller target arbitrary process instances.
**Authorize cancellation in the application**
The engine runs the event subprocess it is told to run, but it does not decide whether the caller is allowed to cancel a case or process. Put the authorization check in your application layer, in the service or API that receives the cancellation request, before it sends a message or signal to the engine. Confirm that checks cover both the caller's identity and ownership of the specific process instance, not only the role.
Audit trail through engine history
Event subprocess starts, interruptions and completions are recorded in engine history, which gives you a trace of when a cancellation or status request ran. Decide which history level you need, where the data is stored, and how long it is retained. Note that history records what the engine did, not who was entitled to request it, so record the requesting user in your own application logs as well.
Timers across nodes
Timers in event subprocesses are fired by the async executor, which runs jobs from a thread pool on each node. Nodes coordinate through lock owners and lock expiration times stored in the database, so when a node fails its expired locks are recovered and another node picks up the job. Confirm your cluster shares one database, size the lock expiration for your workload, and test a node failure during a pending timer.
Interrupting timers and duplicate firing
A timer that is interrupting cancels the enclosing scope when it fires, so an unintended trigger can end work that people expect to continue. Review every timer on event subprocesses for its interrupting setting and its schedule, and document who owns each one. Verify with a test that a timer cannot fire twice after a lock is recovered on another node.
Operational checks before release
Before a model with event subprocesses goes live, agree a checklist covering sender accounts, cancellation authorization, history retention and timer behavior under node failure. Record the result of each check as evidence for reviewers. Ask your Flowable contact or DeployOpen to confirm each item against your deployment, since the answers depend on your database, cluster layout and application code.
Questions teams ask before building event subprocesses
What drives the effort of adding event subprocesses to an existing model?
The main driver is how many process scopes need event handling and how many of those events have real business meaning. Each event subprocess needs a defined trigger, a clear rule for whether it interrupts the parent scope, variables it reads and writes, and a path back to a valid state. Effort rises when the existing model has deep embedded subprocesses, shared variables with unclear ownership, or service tasks whose side effects must be compensated when an event cancels work. Adding a simple status request handler to a flat process is far less work than retrofitting cancellation across several nested scopes. Ask any partner to list the scopes, events and downstream systems they expect to touch before agreeing a scope.
Can our internal team build event subprocesses without a partner?
Often yes, if the team already runs Flowable in production and has engineers who know BPMN semantics, the Flowable engine's transaction behavior and the async executor. The hard part is rarely drawing the event subprocess. It is deciding what happens to in-flight work, which external calls can be repeated safely and how the business accepts a cancellation. Teams without that experience usually find the gaps during testing with live-like data. A useful check is whether two or three engineers can explain, for each event, what state the instance is in before and after the event fires. If not, a short design review with an outside engineer can close the gap before build starts.
What does the work need from our domain experts, test data and environments?
Event subprocesses encode business rules about when work may be stopped, so domain experts must confirm the rules for each event: who may cancel, what counts as an error, which timers are business deadlines and what a status answer must contain. Engineering needs representative test data, including instances in several states, so that interrupting and non-interrupting paths can be exercised. You will also need a non-production environment that matches the database type, Flowable version and identity source of production, plus access to the systems the handlers call, or stubs for them. Ask the partner which of these inputs they expect from you and when, because missing decisions are the most common cause of rework.
How do timing and scope affect how long the build takes?
Timing depends on the number of events, how many scopes they attach to and how much each one changes existing behavior. Timer-based events need careful checks of ISO 8601 durations, time zones and how the async executor fires jobs after a restart. Message and signal events depend on the correlation keys and on whether other systems already send them. Interrupting events that cancel work in progress usually need the most testing, because they must be checked against open tasks, called processes and compensation. Ask for a written list of the events in scope, the test cases each one needs and the points where your team must provide input. A fixed-scope agreement makes these dependencies visible before work starts.
What is the difference between interrupting and non-interrupting event subprocesses in practice?
An interrupting event subprocess ends the parent scope when it fires, cancelling the active activities inside it, so it suits cancellation or a hard error that must stop normal work. A non-interrupting event subprocess runs alongside the normal flow, so it suits status requests, reminders or notifications that should not disturb the main path. The choice affects variables, open tasks and any service calls in progress, so it should be made per event with the business owner. Test both paths for each event, because a non-interrupting handler that writes shared variables can change results on the main path if it runs at the same time.
How should we compare partner quotes for event subprocess work?
Compare quotes on the written scope rather than on totals alone. A usable quote lists each event, the parent scope it attaches to, the handler behavior, the integrations and test cases included, and the inputs expected from your team. Check whether the quote covers design review, implementation, automated tests, documentation of the model and knowledge transfer to your engineers. Ask which costs are one-time and which recurring, such as support or retainer work after go-live, and what changes the scope if a later event is added. DeployOpen does not publish a price list, so the quote follows from the agreed scope, and you should ask every bidder to price the same list of events.
What should we check on a Flowable version before adding event subprocesses?
Confirm the Flowable version, the Java and Spring baseline and the database type before you write any handler, because behavior and packaging differ across major versions. The Flowable release notes list the Java, Spring and Jakarta requirements for each major version, and the configuration docs list the supported databases and their precision limits for timestamps. Make sure your test environment uses the same version as production and that any upgrade is planned separately from the event work. Ask the partner to state which version the design targets and whether any part of the design depends on a feature from a later release.
Limits to confirm in your Flowable version and environment
Event subprocess behavior is tied to the engine version, the database and the async executor underneath it. The cards below list the items to verify before you commit to a design. Confirm each one against the vendor documentation for your exact version or in a test environment that matches production.
Engine version and Spring baseline
Flowable 7.0.0 moved to Java 17, Spring Boot 3 and Jakarta EE, and Flowable 8.0.0 moved to Spring Framework 7 and Spring Boot 4 without backward compatibility for Spring Boot 3. Event subprocess examples written against one baseline may not compile or behave the same on another. Check the release notes for your target version and rerun your event subprocess tests after any change to the Spring or Java baseline.
Version-specific event semantics
Interrupting and non-interrupting behavior for error, message, signal and timer starts should be confirmed for the engine version you run, not inferred from general BPMN texts. Write a small test per event type that cancels a running scope and checks which tokens survive. Record the results in your design notes so a later upgrade can be compared against them.
Supported database and history settings
Flowable lists H2, MySQL, Oracle, PostgreSQL, DB2 and Microsoft SQL Server as supported database types. Event subprocess state and history are written to these tables, so confirm the exact database version and the history level you plan to use. For MySQL, confirm that your server version supports the millisecond precision that timer and history ordering depend on.
Timer precision on your database
Timer start and boundary events inside an event subprocess fire on times stored in the database. Versions of MySQL below 5.6.4 lack millisecond precision, which can shift when a timer fires relative to a status request or cancellation. Test a timer that is due within a few seconds of a cancel signal and confirm which one the engine applies first on your database.
Async continuations and the job executor
Timers and asynchronous jobs run through the async executor, which uses lock owners and lock expiration times in the database to coordinate nodes. If a task inside an event subprocess has an async continuation, cancellation and status requests may wait for a job to run on another node. Confirm how long jobs wait under your node count and lock settings, and test a cancel while an async job is locked.
Migrated instances with active event scopes
If you are moving running instances from Camunda 7 or Activiti, confirm how existing event subscriptions and active event subprocess scopes are carried across the migration. A definition change that adds or renames an event subprocess can leave instances without the handler they expect. Test migration with at least one instance that is waiting inside an event scope.
What DeployOpen needs from your team to scope event subprocess work
Before DeployOpen can write a fixed-scope quote for event subprocess work, we need a process inventory that lists every Flowable process and case definition that will receive error, message, signal or timer events, with its owner, its current version and the number of running instances. Include whether each process is started by a message or signal, which embedded subprocesses already exist, and which call activities reach into other deployments. This inventory sets the count of models to change and tells us where interrupting and non-interrupting event subprocesses would affect work already in flight.
Next we need an event catalog and the correlation rules behind it. For each event, the catalog should name its source system, its payload fields, its expected frequency and what the business expects to happen when it arrives during the subprocess. Correlation rules state which business key, variable or message name links an incoming event to a running instance, and what the team does when no instance matches or several do. Ask your team to confirm how cancellation and status requests are authorized, because the engine does not decide who may cancel a case or read its state. Those answers drive how much of the work is modeling and how much is application code and API design.
Finally, state your environments and test expectations in writing. Tell us which environments exist for Flowable, how deployments reach them, whether the engine runs embedded in your Spring Boot services or behind the REST application, and which database the team uses. Describe the test evidence you will accept, such as scenario tests for each boundary event, replay of recorded messages, and load checks for timers that fire in bulk. DeployOpen states scope, deliverables and timelines in writing before any work starts, so any open question in these inputs should be recorded as an assumption or an exclusion in that agreement rather than left for the build phase.
How DeployOpen scopes, builds and supports Flowable event subprocesses
DeployOpen plans, implements, tests, documents and supports Flowable engines inside your own infrastructure, including the event subprocess designs covered on this page. Engagements start from a written scope that names the process models, event types and integrations involved, so you know what will be delivered before work begins.
How we scope
- Inventory the process models where error, message, signal or timer events must act across the whole scope
- Record which event triggers interrupt running work and which run alongside it, agreed with process owners
- Define cancellation and status request behavior, including which callers may send them and what they receive
- Fix the deliverables, test cases and timelines in writing before build work starts, as engagements are fixed-scope
How we build
- Model event subprocesses in BPMN with interrupting and non-interrupting starts set explicitly for each trigger
- Connect message and signal events to your correlation keys, tenant scope and error mapping conventions
- Configure the async executor and timer behavior so events fire reliably across every node in your cluster
- Test each trigger path, including overlapping events, cancellation during active work and repeated delivery
How we hand over
- Deliver process definitions, delegate code and configuration in your version control with a documented deployment path
- Document each event subprocess with its trigger, scope, variables read and written, and expected end states
- Provide runbooks for failed jobs, stuck event waits and status request responses used by operations staff
- Walk your engineering and operations teams through the test results and the open decisions left for them
How we support
- Available as a retainer for Flowable upgrades, model changes, monitoring review and regression testing
- Retainers can cover updates to event subprocesses when Flowable versions or business rules change
- Confirm during scoping which support hours, response expectations and escalation paths your retainer will include
- Re-run event scenario tests after each change so interrupting and non-interrupting behavior stays as designed

