Routing Events to Processes

In order to start a new process instance or to route a message to an already running instance you have to choose the appropriate technology option to do so, ranging from using forms, the Java or REST API or even customized possibilities including SOAP Web Services or JMS. Leverage the Java universe and the frameworks of your choice to support the technologies or protocols you need.
Routing Events to Processes is also related to
Routing Events to Processes

Choosing the right BPMN Event

Start Events

Several BPMN start events can be used to start a new process instance.

None Event

Message Event

Timer Event

Signal Event

Conditional Event

none start

message start

timer start

signal start

conditional start

Use When

You have only one start event or a start event which is clearly standard.

You have to differentiate several start events.

You want to automatically start process instances time controlled.

You need to start several process instances at once. Rarely used.

When a specific condition is met, a process instance is created.

Supported for Execution

Determine occurrence of condition externally yourself and send message event to the process engine.

Learn more

Learn more

Learn more

Learn more

Learn more

1 This "none start event" indicates the typical starting point. Note that only one such start event can exist in one process definition.
2 This message start event is defined to react to a specific message type, …​
3 …​hence you can have multiple message start events in a process definition. In this example both message start events seems to be exceptional cases - for equivalent cases we recommend to just use message instead of none start events.

Intermediate Events

Several BPMN intermediate events (and the receive task) can be used to make a process instance wait for and react to certain triggers.

Message Event or Receive Task

Timer Event

Signal Event

Conditional Event

message intermediate

task receive

timer intermediate

signal intermediate

conditional intermediate

Use When

You route an incoming message to a specific and unique process instance.

As alternative to message events (to leverage BPMN boundary events, e.g. for timeouts).

You want to make your process instance wait for a certain (point in) time.

You route an incoming signal to all process instances waiting for it.

When a specific condition is met, the waiting process instance moves on.

Supported for Execution

Learn more

Learn more

Learn more

Learn more

Learn more

1 This intermediate message event causes the process instance to wait unconditionally for a specific event…​
2 …​ whereas the intermediate message event attached to the boundary of an activity waits for an optional event potentially arriving while we are occupied with the activity.

Using API Methods to Route Events to Processes

Starting Process Instances By Key

If you have only one starting point, you reference the process definition by the ID in the BPMN XML file. This is the most common case.

processEngine.getRuntimeService().startProcessInstanceByKey('invoice'); (1)
1 Process ID defined in the BPMN. The API calls this ID the "Key" of the process.

Retrieve the Process Engine by injecting it - or do a programmatic lookup if this is not possible:

@Inject
private ProcessEngine processEngine; (1)

public ProcessEngine getEngineProgramatically() {
   return BpmPlatform.getDefaultProcessEngine(); (2)
}
1 The easiest way is normally to inject the Process Engine, this works out-of-the-box using Spring or CDI.
2 As an alternative you can actively get the Process Engine by a static method.

See the Process Engine API for more details.

Starting Process Instances By Message

As soon as you have multiple possible starting points you have to use named messages to start process instances.

processEngine.getRuntimeService()
  .createMessageCorrelation('message_invoiceReceived') (1)
  .setVariable("invoiceId", "123456") (2)
  .correlate();
1 Message Name defined in the BPMN
2 Payload delivered with the message
On one hand, now you do not have to know the key of the BPMN process. On the other hand, you cannot influence the version of the process definition used when starting a process instance by message.
The message name for start events has to be unique to the whole Process Engine - otherwise the engine will not know which process to start.

Starting Specific Versions of Process Instances By Id

See Versioning Process Definitions for details on versioning of process definitions.

By default the Process Engine always starts the newest version of a process definition. You can start a specific version of a process definition by referencing the ID (primary key) of that definition in our process engine database.

ProcessDefinition processDefinition = processEngine().getRepositoryService()
  .createProcessDefinitionQuery()
  .processDefinitionKey("invoice")
  .processDefinitionVersion(17)
  .singleResult();
processEngine().getRuntimeService()
  .startProcessInstanceById(processDefinition.getId());
"By ID" does NOT relate to the ID in the BPMN XML file (which is known as "Key" in the Process Engine). Instead, ID relates to the primary key in the Camunda database. You don’t have influence on this ID - it will be created during deployment time.

Correlating Messages to Running Process Instances

In case you want to route an event to a process instance already started, you will need to correlate the message to the specific process instance waiting for it by matching some properties of the incoming message to some properties of your process instance:

runtimeService
  .createMessageCorrelation("myMessage") (1)
  .processInstanceBusinessKey(myMessage.getOrderId().toString()) (2)
  .processInstanceVariableEquals("customerId", myMessage.getCustomerId()) (3)
  .correlate();
1 A process instance matches if it is waiting for a message named myMessage, …​
2 if it carries the orderId of the message as its business key, …​
3 and if a process variable "customerId" also matches the expectations.
As a best practice, correlate incoming messages based on one unique artificial attribute (e.g. "correlationIdMyMessage") created specifically for this communication. Alternatively you also have the option to select the process instance targeted by a message based on a query involving complex criteria and then as a second step explicitly correlate the message to the selected process instance.

The API docs show more details about the possibilities to trigger message events.

Routing Signals to Process Instances

In the case of a BPMN Signal, a correlation to a specific process instance is neither necessary nor possible, as the mechanism is meant to inform all process instances "subscribing" to a specific signal event:

runtimeService
  .createSignalEvent("mySignal") (1)
  .setVariables(variables) // pass variables (optional)
  .send();
1 A process instance matches if it is waiting for or started by a signal named 'mySignal'.

Starting Process Instances at Arbitrary Nodes

There are use cases when you want to start a process instance at some point other than the modeled start event:

In these cases you can start a process instance in arbitrary activities using the API.

1 This example starts the twitter process directly before the "Publish on Twitter" Service Task, meaning the Service Task will be executed:
processEngine.getRuntimeService().createProcessInstanceByKey("twitter")
  .startBeforeActivity("service_task_publish_on_twitter")
  .setVariable("content", "Know how to circumvent the review!")
  .execute();

Reacting to Internal Process Events

Events relevant for the process execution do not always happen outside of the process instance and hence must be explicitely "routed" to it. They can also occur inside. Consider the following loan application process - or at least the initial part with which the applicant’s income is confirmed either via the employer or via the last income tax statement.

1 In case the employer does not confirm the income within three business days, a timer event triggers and a human clerk now tries to contact the employer and investigate the situation.
2 This could end with a succesful income confirmation. However, it could also end with new findings regarding the applicant’s employment status. We e.g. learn that the applicant is actually unemployed.
3 In this case a conditional event watching this data (e.g. a process variable changed by the human task) triggers and causes the process to reconsider the consequences of the new findings.
A conditional event’s condition expression is evaluated at it’s "scope" creation time, too, and not just when variable data changes. For our example of a boundary conditional event, that means that the activity it is attached to could principally be left immediately via the boundary event. However, our process example evaluates the data via the exclusive gateway - therefore such a scenario is semantically impossible.

Bonus  Using the Camunda BPMN Framework

If you use the Camunda BPMN Framework as described in our book "Real Life BPMN" you will typically have Message Start Events (even if you only have a single start event) to connect the surrounding human flows to the technical flow via messages:

1 This is a "Message Start Event" - which allows you to show the collaboration between the human and the technical flows. However - it is the only starting point of the technical pool and could be a "None Start Event" in terms of execution.

If there is exactly one message start event for the whole process definition it can also be treated as if it where a none start event when starting a process instance in the Camunda engine: you can still start the process by key.

Bonus  Technology Examples for Messages Sent by External Systems

The Camunda process engine is by design not concerned with the technical part of receiving external messages. This means you have to receive the message by means of your platform-specific activities such as connecting to a JMS (Java Messaging Service) Queue/Topic or processing a Webservice or REST request and then route it to the process engine.

You will also have to consider the nature of the message. It might also be a human user, who receives a process relevant business message by conventional means like e.g. eMail. This is further looked at in another bonus section.

In this section we concentrate on technical messages, which are received from other systems, typically by leveraging technologies like e.g. SOAP, REST, JMS or other.

1 You will need a mechanism receiving that message and routing it to the Camunda process engine. That could be a direct REST call to the Camunda API. It could also be a JMS consumer or a SOAP endpoint using the Camunda Java API internally. It could even be a hotfolder polled by Apache Camel.

The following table lists the features of Camunda which can be used to build a method of receiving messages.

Java

REST

Apache Camel

Process instances are informed about message/signal events by calling the Java API

Process instances are informed about message/signal events by calling the REST API

Process instances are informed about message/signal events by using Apache Camel Routes.

Use when

Default choice for implementing message delivery from other process instances, external systems or users.

Alternative when communicating remotely or using a non Java programming languages.

Alternative when you already (plan to) use Camel or to leverage certain Camel Components.

Support

Camunda Core Product

Community Extension (unsupported)

Learn more

Learn more

Learn more

Example: Messages sent via SOAP Web Services

To start a process instance via a SOAP message write some Java code, e.g. by leveraging the @WebService annotation in a Java EE container.

@WebService(name = "InvoiceService") (1)
public class InvoiceService {

  @Inject
  private RuntimeService runtimeService; (2)

  public void startInvoice(String invoiceId) {  (3)
    Map<String, Object> variables = new HashMap<String, Object>();
    variables.put("invoiceId", invoiceId);
    runtimeService.startProcessInstanceByKey("invoiceId", variables);
  }

}
1 The @WebService annotation is sufficient to provide the SOAP web service
2 You can inject the process engine or the process engine services when using a proper dependency injection container like CDI
3 Decide if you prefer to use a business interface (like shown here) or a generic one like "startProcessInstance"

Example: Messages sent via JMS

To start a process instance by a JMS message write some Java code, e.g. use a message driven bean in a Java EE container.

@MessageDriven(name = "InvoiceMDB", activationConfig = {
    @ActivationConfigProperty(propertyName = "destinationType",
                              propertyValue = "javax.jms.Queue"),
    @ActivationConfigProperty(propertyName = "destination",
                              propertyValue = "queue/invoice")
  }
)
public class InvoiceMDB implements MessageListener {

  @Inject
  private RuntimeService runtimeService;

  @Override
  public void onMessage(Message message) {
    try {
      String invoiceId = ((TextMessage) message).getText();
      Map<String, Object> variables = new HashMap<String, Object>();
      variables.put("invoiceId", invoiceId);
      runtimeService.startProcessInstanceByKey("invoice", variables);
    } catch (Exception ex) {
      throw new RuntimeException("Could not process JMS message", ex);
    }
  }
}

Example: Messages sent via REST

The REST API can be directly used to communicate with the Process Engine remotely.

POST /process-definition/key/invoice/start

Request body:
{
  "variables": {
      "invoiceId" : {"value" : "123456", "type": "String"}
  }
}

More information can be found in the REST API Reference.

Example: Messages sent via Apache Camel (e.g. File Handling)

Use Apache Camel if you want to use one of the existing Camel Components (a huge list). Consider leveraging the Camunda Camel Community Extension. You can find an example of this in action on JBoss/Wildfly in this showcase (unsupported).

Starting a process instance can be done by a Camel route, e.g. when a file was placed into a drop folder:

from("file://c:/tmp") // some drop folder
    .routeId("file")
    .convertBodyTo(String.class) // convert content of file into String
    .to("log:org.camunda.demo.camel?level=INFO&showAll=true&multiline=true") // optional logging
    .to("camunda-bpm:start?processDefinitionKey=invoice"); // and start new process instance
In this case the message transported within the Camel route is handed over to the process instance as a variable named camelBody by default, see documentation.

Example: Messages sent via an Enterprise Service Bus (ESB)

If you have an ESB in your architecture you may want to start process instances from your ESB. The best approach to do this depends on the concrete product you use. There are two basic possibilities how you do this:

  • Java: You call the engine inside the VM via the Java API, like it is done in the Camunda Camel Community Extension.

  • Remote: You call a remote API (e.g. Camunda REST) to communicate with the engine. You might also build your own endpoint (e.g. JMS or SOAP) as described above.

Currently we only know of Camel supporting the way of In VM integration.

Bonus  Sending Messages to Other Processes

If messages are exchanged between different processes deployed in your Camunda container you have to implement the communication yourself, typically by a JavaDelegate using API to start a new process instance by key, start a new process instance by message or to correlate the message to a running process instance.

1 Use a simple Camunda JavaDelegate on the sending process' side, to route the message to a new process instance, e.g. by key.
2 Use a simple Camunda JavaDelegate on the sending process' side, to correlate the message to a running process instance ready to receive it.
public class SendOrderReceivedMessageDelegate implements JavaDelegate {

  public void execute(DelegateExecution execution) throws Exception {
    Map<String, Object> variables = new HashMap<String, Object>();
    variables.put("invoiceId", execution.getVariable("invoiceId"));
    execution.getProcessEngineServices().getRuntimeService()
      .startProcessInstanceByKey("invoice", variables);
  }

}
public class SendPaymentReceivedMessageDelegate implements JavaDelegate {

  public void execute(DelegateExecution execution) throws Exception {
    Map<String, Object> variables = new HashMap<String, Object>();
    variables.put("paymentInformation", execution.getVariable("paymentInformation"));

    String orderId = execution.getVariable("orderId");

    execution.getProcessEngineServices().getRuntimeService()
      .createMessageCorrelation("MsgPaymentReceived")
      .processInstanceVariableEquals("orderId", orderId)
      .setVariables(variables)
      .correlate();
  }

}

Bonus  Handling Messages Sent by a User

Sometimes explicit "user tasks" are not an appropriate choice to involve a human user to participate in a process: the user does not want to see a task in the tasklist, but rather have the possibility to actively trigger some action right at the time when it becomes necessary from a business perspective. The difference is which event gives the active trigger.

1 We did not model a user task in this process, as the user will not immediately be triggered. He or She cannot do anything at the moment when the process enters this event. Instead we made it wait for a "message" which is later triggered by a human user.
2 The accountant actually receives the "external trigger" by actively looking at new payments in the bank account.
3 Every new payment now has to be correlated to the right waiting process instance manually. In this situation it is often the better choice not to model a user task, but let the process wait for a "message" generated from a user.
These scenarios are not directly supported by Camunda tasklist. A custom search screen built for the accountant might allow to see and find orders waiting for a payment. By interacting with such a screen, the accountant communicates with those process instances all at once. When hitting a 'Paid' button, a piece of custom server code e.g. using the Java API or a piece of custom client code e.g. using the REST API must now correlate the user’s message to the affected instance(s).

No guarantee - The statements made in this publication are recommendations based on the practical experience of the authors. They are not part of Camunda’s official product documentation. Camunda cannot accept any responsibility for the accuracy or timeliness of the statements made. If examples of source code are shown, a total absence of errors in the provided source code cannot be guaranteed. Liability for any damage resulting from the application of the recommendations presented here, is excluded.

Copyright © Camunda Services GmbH - All rights reserved. The disclosure of the information presented here is only permitted with written consent of Camunda Services GmbH.