После отправки счёта процесс должен продолжиться по первому из двух событий: оплате или истечению срока. Ан...

После отправки счёта процесс должен продолжиться по первому из двух событий: оплате или истечению срока. Аналитик использовал такой фрагмент BPMN. Какой элемент нужно применить вместо шлюза?

<process id="payment">
  <parallelGateway id="waitForResult"/>
  <intermediateCatchEvent id="paymentReceived"/>
  <intermediateCatchEvent id="deadlineReached">
    <timerEventDefinition/>
  </intermediateCatchEvent>
</process>
Проходите собеседования с ИИ помощником Hintsage

Краткий ответ

Вместо parallelGateway нужен шлюз, основанный на событияхevent-based gateway. Он выбирает ветвь по первому наступившему событию: оплате или истечению срока; после выбора остальные альтернативы больше не участвуют в ожидании.

Исторический контекст

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

Шлюз, основанный на событиях, решает задачу, в которой заранее неизвестно, какой из взаимоисключающих триггеров произойдёт первым. Это отличается от выбора по уже известному логическому условию.

Постановка проблемы

Параллельный шлюз запускает все исходящие ветви одновременно и обычно требует синхронизации последующих потоков. В данном сценарии оплата и истечение срока — альтернативные события, поэтому запуск обеих ветвей не отражает бизнес-смысл.

Если процесс ждёт оба результата, он может задержаться после оплаты до наступления таймера. Если одна из ветвей не должна завершаться никогда, процесс может остаться в незавершённом состоянии. Кроме того, параллельный шлюз не выражает правило «побеждает первое событие».

Подробное решение

После event-based gateway размещают события, которые процесс способен поймать: например, событие получения сообщения об оплате и промежуточное таймерное событие. Процесс ожидает их одновременно, но продолжает выполнение только по ветви события, наступившего первым.

<process id="payment"> <eventBasedGateway id="waitForResult"/> <intermediateCatchEvent id="paymentReceived"> <messageEventDefinition messageRef="paymentMessage"/> </intermediateCatchEvent> <intermediateCatchEvent id="deadlineReached"> <timerEventDefinition/> </intermediateCatchEvent> </process>

В этом фрагменте шлюз не проверяет выражение вроде статуса платежа. Он создаёт ожидание событий, а тип события определяет выбранную ветвь. После срабатывания одной альтернативы ожидание других альтернатив прекращается в рамках данного экземпляра процесса.

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

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

Ситуация из практики

Интернет-магазин после создания заказа отправлял счёт и должен был либо подтвердить заказ после уведомления платёжного провайдера, либо отменить его по тайм-ауту. Рассматривались три варианта: параллельный шлюз, исключающий шлюз с проверкой статуса и шлюз, основанный на событиях.

Параллельный шлюз был отклонён: он моделировал одновременное выполнение альтернатив и создавал риск ожидания двух несовместимых результатов. Исключающий шлюз также не подходил сразу после отправки счёта, поскольку в этот момент статус оплаты ещё мог быть неизвестен и требовал отдельного механизма ожидания.

Выбрали event-based gateway с сообщением об оплате и таймером. После этого оплата переводила заказ в подтверждённое состояние, а таймер — в отменённое; поздние уведомления обрабатывались отдельным правилом идемпотентности. Это устранило зависание процесса и сделало правило выбора ветви явным.

Что кандидаты часто упускают

  1. Чем event-based gateway отличается от exclusive gateway?

    Исключающий шлюз выбирает исходящий поток на основании условий, вычисляемых по данным или состоянию процесса. Event-based gateway не вычисляет такие условия: он ожидает наступления событий и выбирает поток по тому, какое событие произошло первым.

  2. Можно ли после event-based gateway разместить обычную задачу?

    Непосредственно после такого шлюза обычно размещают элементы, способные ожидать или фиксировать событие: например, сообщение или таймер. Обычная задача сама по себе не является событием, поэтому её размещение может нарушить ожидаемую семантику модели или зависеть от ограничений конкретного инструмента.

  3. Что произойдёт с поздним событием после выбора одной ветви?

    Альтернативное ожидание прекращается для данного экземпляра процесса. Однако внешняя система может всё равно доставить позднее сообщение, поэтому обработчик должен корректно игнорировать его, сопоставить с уже закрытым заказом или запустить предусмотренный компенсационный сценарий. Это нужно явно зафиксировать в требованиях, иначе корректная BPMN-модель не гарантирует корректное поведение интеграции.