25.03.20

Маршрутизация событий в процессах

15 мин · Обучающие

Для того, чтобы запустить новый экземпляр процесса или направить сообщение на уже функционирующий инстанс, необходимо выбрать наиболее подходящий инструмент: Java, REST API, SOAP Web Services или JMS. Начнем с короткого обзора стартовых событий.

Оригинал статьи на английском языке размещен тут: Routing Events to Processes

Маршрутизация событий в процессах

Выбор корректного BPMN события


Стартовые события. Для запуска нового процесса может быть использовано несколько стартовых BPMN. Рассмотрим случаи использования различных стартовых событий: Типы стартовых событий

  1. None Event – в процессе одно стартовое событие или условие для запуска экземпляра процесса не указано.
  2. Message Event – используется в случае, когда необходимо различать несколько стартовых событий.
  3. Timer Event – автоматический запуск процесса контролируется таймером.
  4. Signal Event – необходимо запустить сразу несколько инстансов (редко используется).
  5. Conditional Event – запускает событие при выполнении определенного условия.

Рассмотрим следующий процесс в качестве примера: Стартовые события в процессе BPMN

  1. None start event показывает типичную отправную точку процесса. Еще раз отмечу, что только одно подобное стартовое событие может существовать в процессе.
  2. Это message start event начнет процесс при получении определенного сообщения извне.
  3. В процессе может быть несколько message start event. В данном примере оба message start event оказались исключительными случаями, в подобных ситуациях лучше использовать вместо none start события message start event.

Промежуточные события. Несколько промежуточных BPMN событий (и задач-получения сообщения) могут быть использованы для того, чтобы заставить инстанс процесса ждать и реагировать на определенные триггеры.

Типы промежуточных событий

  1. Message Event - используется, когда направляем сообщение конкретному и уникальному экземпляру процесса.
  2. Receive Task – очень похож на message event, но используется для того, чтобы дополнительно использовать boundary events.
  3. Timer Event – используется, когда хотим заставить инстанс процесса ожидать некоторое время.
  4. Signal Event – используется, когда направляем сигнал всем инстансам процесса, ожидающим его.
  5. Conditional Event – как только определенное условие выполнено, процесс продолжается.

Рассмотрим пример:

Промежуточные события в процессе BPMN

  1. Процесс не сдвинется с этой точки до тех пор пока не будет получено сообщение.
  2. До тех пор пока токен находится на активности “Order fulfillment”, процесс может принять сообщение “Order canceled”.

Использование методов API Camunda для маршрутизации событий в процессах

Запуск процесса по ключу. Если в процессе одно стартовое событие, то достаточно сослаться на определение этого процесса по идентификатору в BPMN XML файле. Это наиболее часто встречающийся случай.

processEngine.getRuntimeService().startProcessInstanceByKey("invoice"); 


Идентификатор процесса определен в BPMN. API называет этот идентификатор ключом (Key) процесса. Чтобы извлечь processEngine необходимо либо инджектировать его (самый простой путь, это работает out-of-the-box используя Spring или CDI), либо осуществить поиск следующим образом:

@Inject
private ProcessEngine processEngine; 

public ProcessEngine getEngineProgramatically() {
   return BpmPlatform.getDefaultProcessEngine(); 
}

Запуск процесса с помощью сообщения. Как только в процессе появляется несколько отправных точек необходимо использовать именованные сообщения для старта процесса. Названия стартовых событий должны быть уникальными в рамках всего Process Engine, иначе движок не сможет определить какой именно процесс запускать.

    
    processEngine.getRuntimeService()
      .createMessageCorrelation("message_invoiceReceived") 
      .setVariable("invoiceId", "123456") 
      .correlate();

  1. message_invoiceReceived – имя сообщения, определенное в BPMN-модели процесса
  2. ("invoiceId", "123456") – то, что передается инстансу вместе с сообщением

С одной, стороны для запуска процесса таким способом не нужно знать ключ BPMN процесса. С другой стороны, мы не можем никак повлиять на версию процесса, который будет запущен.

Запуск определенной версии процесса по идентификатору. По умолчанию Process Engine всегда стартует самую новую версию процесса. Запуск определенной версии процесса возможен по ссылке на ID (primary key) этой версии процесса из process engine database.

    
    ProcessDefinition processDefinition = processEngine().getRepositoryService()
        .createProcessDefinitionQuery()
        .processDefinitionKey("invoice")
        .processDefinitionVersion(17)
        .singleResult();
    processEngine().getRuntimeService()
        .startProcessInstanceById(processDefinition.getId());


В данном случае имеется в виду не ID из BPMN XML файла (который еще называется ключом (key) в Process Engine), а ID который можно назвать первичным ключом (primary key) базы данных Camunda. На этот ID невозможно повлиять, он создается во время deployment time.

Корреляция сообщений к уже запущенным инстансам процессов.

Чтобы отправить сообщение процессу, ожидающему это сообщение, достаточно сопоставить некоторые свойства входящего сообщения с некоторыми свойствами ожидающего процесса. Эта процедура называется корреляцией (corellate message).

    
runtimeService
  .createMessageCorrelation("myMessage") 
  .processInstanceBusinessKey(myMessage.getOrderId().toString()) 
  .processInstanceVariableEquals("customerId", myMessage.getCustomerId()) 
  .correlate();

  1. myMessage – имя сообщения, которое ждет процесс
  2. processInstanceBusinessKey(myMessage.getOrderId().toString) - если процесс содержит orderId сообщения в качестве своего бизнес ключа
  3. и если переменная процесса “customerId” также соответствует ожиданиям.

Лучше всего коррелировать входящие сообщения на основе одного уникального атрибута (например "correlationIdMyMessage"), созданного специально для этого сообщения. В качестве альтернативы также есть возможность выбрать экземпляр процесса, на который нацелено сообщение, на основе запроса, включающего сложные критерии, а затем в качестве второго шага явно коррелировать сообщение с выбранным экземпляром процесса.

Маршрутизация сигналов. Корреляция с конкретным экземпляром процесса при использовании сигнала - невозможна. Механизм сигналов предназначен для информирования сразу нескольких экземпляром процесса, которые подписаны на конкретное событие сигнала:

    runtimeService
  	.createSignalEvent("mySignal") 
  	.setVariables(variables) // pass variables (optional)
  	.send();

- mySignal – имя сигнала, который ждут инстансы процессов