Skip to content

Decisions and supported features#

Spring Boot compatibility#

The embedded Spring Boot starter requires Spring Boot 4, matching the Operaton 2.x Spring Boot starters. The scheduler auto-configuration uses adapter-owned threading conditions instead of Spring Boot's removed Threading.VIRTUAL and Threading.PLATFORM enum values.

If spring.threads.virtual.enabled=true and the application runs on Java 21 or newer, the starter contributes a SimpleAsyncTaskScheduler for Spring's default taskScheduler bean. Otherwise, it falls back to a ThreadPoolTaskScheduler.

The examples use Operaton 2.1.3, published on Maven Central.

Embedded Spring Boot 4 applications need a working DataSource and transaction manager, for example via spring-boot-starter-jdbc — since the Spring Boot 4 module split, the JDBC auto-configurations are not brought in transitively by the engine starter. Applications that persist custom object variables as JSON should add operaton-engine-plugin-spin and operaton-spin-dataformat-json-jackson; the Jackson-2 example uses those dependencies to serialize the sample LocalDateTime payload.

Jackson and Spin compatibility#

The adapter starter can serialize adapter payloads with either Jackson 2 or Jackson 3, depending on what the application provides on the classpath. For embedded Operaton, that adapter-level flexibility is narrower once Spin is involved.

Operaton Spin's JSON integration is tied to the Jackson 2 ecosystem. Because of that:

  • Embedded Operaton with Spin JSON serialization must stay on Jackson 2 for the adapter-facing serialization path.
  • Embedded Operaton with Jackson 3 should not use Spin JSON serialization.
  • Embedded Jackson 3 setups should avoid forcing operaton.bpm.default-serialization-format=application/json unless they provide a different compatible JSON variable serialization strategy.
  • Embedded Jackson 3 can still work when object variables use Java serialization instead of Spin JSON serialization.

The provided examples reflect these supported combinations:

  • examples/java-operaton-embedded: embedded example with Spin and Jackson 2
  • examples/java-operaton-embedded-jackson3: embedded example without Spin and with Jackson 3

If an embedded application ends up with both Jackson ecosystems on the classpath, the starter prefers Jackson 3 by default. When Spin is present, provide an explicit AdapterDataConverter bean backed by Jackson 2 so the adapter matches Spin instead of relying on the default selection.

Configuration#

All embedded adapter properties use the prefix dev.bpm-crafters.process-api.adapter.operaton-embedded.

The adapter starter does not bring an embedded Operaton engine on its own. Add it together with an Operaton embedded setup such as operaton-bpm-spring-boot-starter or operaton-bpm-spring-boot-starter-webapp. With the webapp starter, log in with the admin user configured under operaton.bpm.admin-user (the examples use demo / demo).

Minimal classpath#

<dependencies>
  <dependency>
    <groupId>dev.bpm-crafters.process-engine-adapters</groupId>
    <artifactId>process-engine-adapter-operaton-embedded-spring-boot-starter</artifactId>
    <version>${process-engine-adapter-operaton.version}</version>
  </dependency>
  <dependency>
    <groupId>org.operaton.bpm.springboot</groupId>
    <artifactId>operaton-bpm-spring-boot-starter</artifactId>
    <version>2.1.3</version>
  </dependency>
</dependencies>

Minimal YAML#

dev:
  bpm-crafters:
    process-api:
      adapter:
        operaton-embedded:
          enabled: true
          service-tasks:
            delivery-strategy: embedded_scheduled
            worker-id: embedded-worker
          user-tasks:
            delivery-strategy: embedded_scheduled

Delivery strategies#

User tasks#

Value Effect
embedded_scheduled Polls user tasks on the configured schedule and delivers them to subscriptions.
custom Disables the built-in recurring delivery so you can provide your own delivery mechanism.
disabled Disables automatic user-task delivery. The embedded completion/modification APIs are still available because the engine is local.

Service tasks#

Value Effect
embedded_scheduled Uses the built-in scheduler and the local ExternalTaskService to fetch-and-lock external tasks.
custom Disables the built-in recurring fetch loop so you can provide your own delivery mechanism.
disabled Disables automatic service-task delivery. The embedded completion API is still available for tasks delivered by custom code.

Important properties#

enabled#

Turns the embedded adapter on or off. Default: true.

service-tasks.*#

Property Default Description
worker-id required Worker id used for fetch-and-lock and completion calls.
max-task-count 100 Maximum number of external tasks fetched per pull cycle.
lock-time-in-seconds 10 Lock duration for fetched external tasks.
retry-timeout-in-seconds 10 Timeout used by the default failure retry supplier.
retries 3 Initial retry count used by the default failure retry supplier.
delivery-strategy required One of embedded_scheduled, custom, disabled.
schedule-delivery-fixed-rate-in-seconds 13 Polling interval for embedded_scheduled.
execute-initial-pull-on-startup true Triggers one startup pull before the recurring scheduler takes over.

user-tasks.*#

Property Default Description
delivery-strategy required One of embedded_scheduled, custom, disabled.
schedule-delivery-fixed-rate-in-seconds 5 Polling interval for embedded_scheduled.
execute-initial-pull-on-startup true Triggers one startup pull before the recurring scheduler takes over.

Example with explicit scheduling settings#

dev:
  bpm-crafters:
    process-api:
      adapter:
        operaton-embedded:
          enabled: true
          service-tasks:
            delivery-strategy: embedded_scheduled
            worker-id: embedded-worker
            max-task-count: 100
            lock-time-in-seconds: 10
            retry-timeout-in-seconds: 30
            retries: 3
            execute-initial-pull-on-startup: true
            schedule-delivery-fixed-rate-in-seconds: 10
          user-tasks:
            delivery-strategy: embedded_scheduled
            execute-initial-pull-on-startup: true
            schedule-delivery-fixed-rate-in-seconds: 10

Message Correlation#

Correlation API implementation support the following restrictions:

Key Value Description
tenantId The id of the tenant Correlates messages for process instances with given tenant id.
withoutTenantId none If restriction is present, correlate only with process instances without tenant id.
useGlobalCorrelationKey true or false If set to false (default if not set), correlate using local variables, use global process variable otherwise.

Task Information#

Currently, the Process Engine Adapter Operaton Embedded supports the following values in task information meta block, mapped from the Operaton engine:

The TaskInformation.getMeta() provides meta information about the task in form of a Map<String, String> for maximum compatibility. The Original Type column denotes the real type, you want to access if reading the field. For this purpose, TaskInformation offers special access methods getMetaValueAsOffsetDate and getMetaValueAsStringSet.

User Tasks#

Key Original Type Description Example
activityId String Id of the element in BPMN (Task definition key) approve_user_task
processDefinitionId String Id of process definition (given at deployment time) approval_process:912834729348
processDefinitionKey String Id of the process element in BPMN (Process Definition key) approval_process
tenantId String Tenant Id my_tenant
taskName String Name of the user task (from BPMN or modified by the create listener) Approve Order
taskDescription String Description of the user task (from BPMN or modified by the create listener) Approve provided order.
assignee String Assignee of the user task USER12345
candidateUsers Set Set of candidate users, separated by a , USER12345,USER12346,USER12347
candidateGroups Set Set of candidate groups, separated by a , marketing,sales
creationDate OffsetDateTime Time stamp of task creation formatted as ISO-8601 in UTC 2025-05-01T10:00:00.000Z
followUpDate OffsetDateTime Time stamp of task follow-up formatted as ISO-8601 in UTC 2025-05-02T10:00:00.000Z
dueDate OffsetDateTime Time stamp of task due formatted as ISO-8601 in UTC 2025-05-05T10:00:00.000Z
lastUpdatedDate OffsetDateTime Time stamp of task last update formatted as ISO-8601 in UTC 2025-05-05T10:00:00.000Z

Service Tasks#

Key Original Type Description Example
activityId String Id of the element in BPMN (Task definition key) approve_user_task
processDefinitionId String Id of process definition (given at deployment time) approval_process:912834729348
processDefinitionKey String Id of the process element in BPMN (Process Definition key) approval_process
tenantId String Tenant Id my_tenant
topicName String Topic name (from BPMN) for external task topic_approve
creationDate OffsetDateTime Time stamp of task creation formatted as ISO-8601 in UTC 2025-05-01T10:00:00.000Z

Engine Command Executor#

EngineCommandExecutor is an embedded-adapter-specific class that controls how the four core API calls (correlateMessage, sendSignal, startProcess, deploy) are dispatched to the embedded Operaton engine.

By default, all engine calls are submitted asynchronously to ForkJoinPool.commonPool(). This means they run on a different thread from the caller and do not participate in the caller's @Transactional context — a rollback on the calling thread will not roll back the engine operation.

Customizing execution#

Provide a Spring bean of type EngineCommandExecutor to override the default. The auto-configured default is annotated with @ConditionalOnMissingBean, so your bean takes precedence automatically.

Same-thread (synchronous) execution — engine calls run on the calling thread and honour @Transactional:

@Bean
fun engineCommandExecutor(): EngineCommandExecutor =
  EngineCommandExecutor(Executor { it.run() })

Virtual-thread execution — lightweight concurrency without pinning platform threads:

@Bean
fun engineCommandExecutor(): EngineCommandExecutor =
  EngineCommandExecutor(Executors.newVirtualThreadPerTaskExecutor())