A Spring Boot application demonstrating Operaton message events: a process is started by a named message and later resumes when a second message arrives, with correlation by business key.
- Start a process instance via a
messageStartEventusingstartProcessInstanceByMessage() - Suspend a running process at an
intermediateCatchEventuntil a message arrives - Resume a specific process instance by correlating a message to its business key
- Declare messages in BPMN with
<bpmn:message>and reference them from event definitions - Verify active message subscriptions with
EventSubscriptionQuery - Handle
MismatchingMessageCorrelationExceptionwhen no matching instance exists
src/main/resources/order-shipment.bpmn
Message correlation sequence:
- JDK 21
- Docker (for PostgreSQL — both for local runs and the integration tests)
# Make wrappers executable on macOS/Linux
chmod +x mvnw gradlew
docker compose up -d --wait
./mvnw spring-boot:run # or: ./gradlew bootRunOpen http://localhost:8080 — Cockpit and Tasklist, login demo / demo.
Step 1 — Place an order (start process via message):
curl -u demo:demo -H 'Content-Type: application/json' \
-d '{"messageName":"OrderPlaced","businessKey":"ORDER-001","processVariables":{"orderId":{"value":"ORDER-001","type":"String"},"customerId":{"value":"CUST-42","type":"String"}}}' \
http://localhost:8080/engine-rest/messageIn Cockpit you will see the instance paused at Shipment ready.
Step 2 — Mark shipment ready (correlate message):
curl -u demo:demo -H 'Content-Type: application/json' \
-d '{"messageName":"ShipmentReady","businessKey":"ORDER-001","processVariables":{"trackingId":{"value":"TRACK-XYZ","type":"String"}}}' \
http://localhost:8080/engine-rest/messageThe process resumes and completes at Order delivered. Check the trackingId variable in history.
Step 3 — Try correlating to an unknown order:
curl -u demo:demo -H 'Content-Type: application/json' \
-d '{"messageName":"ShipmentReady","businessKey":"ORDER-UNKNOWN"}' \
http://localhost:8080/engine-rest/messageReturns HTTP 400 — no matching process instance subscription found.
- order-shipment.bpmn declares two messages
(
OrderPlaced,ShipmentReady) at the definitions level. The start event and the intermediate catch event each reference one of these messages by ID. startProcessInstanceByMessage("OrderPlaced", businessKey, variables)starts a new process instance via the message start event. The business key becomes the correlation handle for subsequent messages.- After the service task completes, the engine records a message subscription for
ShipmentReadyagainst this process instance. The instance is then suspended in the database — no threads are blocked. correlateMessage("ShipmentReady", businessKey, variables)finds the subscription, delivers the message (merging variables), and resumes execution.- If no subscription exists for the given business key, the engine throws
MismatchingMessageCorrelationException— tested in the IT.
./mvnw verify # or: ./gradlew buildOrderShipmentProcessIT covers three scenarios: the full happy path, duplicate-correlation failure, and independent correlation of two concurrent process instances.
