Book a Demo

Process engine (Process Engine)

The process engine is the system component responsible for executing and managing business processes modeled as BPMN (Business Process Model and Notation) diagrams.

It interprets the process BPMN model and:

  • manages transitions between stages (Activities);
  • tracks process state;
  • handles events (Events);
  • starts tasks for users (User Tasks) and automatic actions (Service Tasks).

In Cabinee, the process engine manages the lifecycle (state model ) of a ticket and creates user and service tasks.

Key principles

  1. Cabinee uses Camunda 8 (Zeebe) as its process engine.

  2. Each space (Workflow) corresponds to a separate tenant in the process engine. A tenant is a logical separator (isolator) inside the process engine that lets you partition access to processes, tasks, and data among different user groups or organizations.

  3. Each ticket that is being processed is mapped to a process instance in the process engine.

  4. The link between a ticket and a process instance is stored in the process variable businessKey, whose value equals the ticket identifier.

Camunda 8 components

Interaction with the engine uses three channels.

Camunda 8 REST API v2 — commands from unibpm-app (Cabinee backend) to the engine: start and cancel instances, message correlation, user-task operations, and reading process definitions and variables.

unibpm-camunda8-exporter — an exporter plugin loaded into the Zeebe broker JVM. It reads the engine record stream and publishes records to Kafka. The exporter is stateless: it does not resolve businessKey or enrich records; it only wraps them in an envelope and sends them to the topic.

unibpm-camunda8-adapter — a separate service. It reads the record stream from Kafka, maintains a processInstanceKey → businessKey mapping table in PostgreSQL, and publishes events to the topics consumed by unibpm-app:

TopicContentsConsumer in unibpm-app
reunico.unibpm.execution.events.prodprocess instance state changesChangeStateConsumer
reunico.unibpm.task.events.produser-task eventsUserTaskEventConsumer

Secondary storage

Runtime state lives in RocksDB inside the broker and is not exposed externally. Everything read through /v2/*/search is written to Elasticsearch by Camunda’s built-in exporter. Export is asynchronous, so search queries lag the actual process state by fractions of a second. A request made immediately after starting an instance may return 404 — this is expected behavior, not an error.

Commands (start, cancel, complete task) go directly to the engine and are not subject to this delay.

Process model and process instance

A process model (Process Definition) is a process description in BPMN 2.0 notation. Working versions are modeled and stored in Cabinee; executable versions are deployed to the process engine.

A process instance (Process Instance) is a specific run (execution) of a process modeled in BPMN. If a business process is a “template” (model), then an instance is its “live execution”, with a unique identifier, current state, variables, and history. Every time a process starts (manually, by an event, or on a schedule), a new process instance is created.

By analogy with OOP: Process Definition is a Class, Process Instance is an instance of the class.

Starting a process instance

Starting a process instance in Cabinee is performed asynchronously using the Transactional Outbox pattern.

This guarantees consistency between the Cabinee database and the process engine, and avoids losing events on failures.

Overall flow

  1. When an event that requires starting a process occurs (for example, ticket creation), the system does not call the process engine directly.
  2. Instead, a row is written to the bd_process_start_outbox table with:
  • ticket identifier;
  • businessKey;
  • process key (processDefinitionKey);
  • tenant identifier (tenantId);
  • process variable set.

This write happens in the same transaction as the business-data change (for example, ticket creation).

Camunda 8 has no native business key, so on instance start the ticket identifier is passed as a regular process variable. The variable name is configured by camunda-eight-client.business-key-variable.

Outbox processing

A background component — ProcessStartWorker — periodically selects rows from the outbox table and starts the corresponding processes in the process engine.

Worker algorithm:

  1. Take a batch of rows from bd_process_start_outbox with status NEW or FAILED.
  2. Lock the row for processing by a specific worker.
  3. Start the process in the process engine.
  4. Obtain processInstanceId.
  5. Store processInstanceId in the outbox table.
  6. Write processInstanceId to the ticket.
  7. Move the outbox row to status DONE.

Protection against duplicate starts

To prevent starting the same process twice:

  • processInstanceId is stored in the outbox immediately after a successful process start;
  • when selecting rows, the worker processes only rows where process_instance_id IS NULL.

This guarantees that even if later processing steps fail (for example, the ticket was deleted), the process will not be started again.

Benefits of the approach

Transactional Outbox provides:

  • atomicity of business-data changes and process-start event enqueueing;
  • resilience to process-engine failures;
  • ability to retry errors;
  • horizontal scaling of workers.

Thus, starting processes in Cabinee is a reliable asynchronous operation that does not affect user-operation transactions.

Stopping a process instance

Camunda 8 has no delete for a running instance: only cancellation is available. The instance moves to state CANCELED, remains visible in Operate and in history, but no longer executes.

Message correlation

Ticket actions and events arriving from outside are sent by Cabinee to the engine as messages. Because Camunda 8 has no native business key, the message is addressed by correlationKey, and Cabinee substitutes the ticket businessKey. If the call does not include businessKey explicitly, it is restored from processInstanceKey via the adapter mapping table.

On the model side, every message event must declare the correlation key as the businessKey variable — see Requirements for Camunda 8 models . On a mismatch, the engine responds that there is no subscription, and the action silently does not take effect.

Moving a ticket to another space or changing the ticket type works as follows: the current instance is stopped, then a new process instance for the new type is started. The ticket’s processInstanceId changes accordingly.