Привет, Хабр!

Меня зовут Михаил, я ведущий разработчик в НЛМК ИТ. Команда, в которой я состою, занимается разработкой и поддержкой различных информационных систем, одной из которых является Единый корпоративный портал ГК НЛМК на базе Битрикс24.

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

Ранее мы уже начинали рассказывать о том, что для унификации и ускорения разработки отдельных сервисов, у нас активно применяется модуль бизнес-процессов Битрикса. 

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

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

Нюансы автозапуска бизнес-процессов у заявок, формируемых в публичной части сайта

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

Настройка автозапуска бизнес-процесса в инфоблоке
Настройка автозапуска бизнес-процесса в инфоблоке

Но здесь зарыт неочевидный момент: штатные API-методы битрикса (напр. CIBlockElement::Add или \Bitrix\Iblock\ElementTable::add) автоматически не инициируют действия над бизнес-процессами. Указанные настройки действуют только при работе в пределах админки битрикса.

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

$iblockId = <id инфоблока>;
$arFields = [<поля элемента>];
 
\Bitrix\Main\Loader::IncludeModule('iblock');
\Bitrix\Main\Loader::IncludeModule('bizproc');
 
$element = new \CIBlockElement();
$id = $element->add($arFields);
 
if ($id) {
    \CBPDocument::AutoStartWorkflows(
        ['iblock', 'CIBlockDocument', 'iblock_' . $iblockId),
        \CBPDocumentEventType::Create,
        ['iblock', 'CIBlockDocument', $id],
        [],
        $arErrors
    );
}

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

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

Активность для публикации элемента
Активность для публикации элемента

Комбинирование классов и бизнес-процессов при создании сервисов

Сложные бизнес-процессы, содержащие дополнительную логику во вставках PHP-кода, имеют ряд сопутствующих проблем:

  • Код в этих вставках выпадает из системы контроля версий.

  • Сложность проведения ревью этого кода, особенно если объем логики большой.

  • Код во вставках не редактируется из любимого IDE, его сложно охватить целиком.

Но эти проблемы легко компенсировать, если построить вставку блоков кода при помощи заранее заготовленных хелперов, хранящихся в общей кодовой базе.

Например, это можно сделать так:

class BizProcTpl10
{
    public static function statusStartEnter(\CBPActivity &$activity): void
    {
        // Логика на входе в статус Старт
    }
  
    // Прочие методы
 
    public static function statusClosedEnd(\CBPActivity &$activity): void
    {
        // Логика в конце статуса Закрыта
    }
}

В таких вставках PHP-кода будет только вызов соответствующего метода хелпера с передачей текущей активности:

BizProcTpl10::statusStartBegin($this->GetRootActivity());

Таким образом, все дополнительные вставки кода оказываются в репозитории системы контроля версий, доступны для проведения ревью и удобно редактируются из IDE.

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

Как не пропустить изменение элемента, если бизнес-процесс находится на паузе?

У заявок (и не только) могут быть ситуации, когда связанный с элементом бизнес-процесс встанет на паузу в ожидании определенного времени.

Например, нам требуется разработать сервис обработки заявок на участие в мероприятии. Согласно бизнес-процессу, после окончания мероприятия его статус должен измениться на "Мероприятие завершено" и запустить следующую за этим цепочку событий (допустим, получение обратной связи, подтверждение участия и т.п.). Очевидным решением для этого процесса будет использование действия "Пауза в выполнении" до даты окончания мероприятия, на которое подана заявка. Этот механизм работает таким образом, что битрикс создает агент, возобновляющий бизнес-процесс в указанную в параметрах паузы дату.

Но в жизни может случиться всякое — мероприятие может быть перенесено или отменено. Созданный при постановке на паузу агент от этого не изменится и так и будет ожидать времени, которое было задано в момент постановки бизнес-процесса на паузу. Соответственно, если в расписании произойдут изменения, он активируется совсем не тогда, когда хотелось бы.

Решить эту проблему можно двумя путями — со стороны кода и непосредственно в бизнес-процессе.

Через код можно повесить перехватчик события на изменение элементов инфоблока мероприятий, проверять в нем наличие ожидающих бизнес-процессов заявок и менять их вручную (путем изменения даты агента или действиями над бизнес-процессом). Но такое решение сразу лишает бизнес-процесс его основного преимущества — наглядности. Из редактора разработчик никак не увидит, что процесс может меняться из перехватчика события.

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

Динамическая пауза в бизнес-процессе
Динамическая пауза в бизнес-процессе

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

Редактирование условия в паузе
Редактирование условия в паузе

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

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

Мастерство параллелизма

Для ветвления бизнес-процессов на несколько идущих друг с другом веток у битрикса есть две конструкции:

  • Параллельное выполнение;

  • Параллельное ожидание действия.

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

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

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

Для всех таких нетиповых ситуаций можно использовать конструкцию параллельного выполнения, из которой, как из пластилина, можно вылепить абсолютно любую логику.

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

На ум сразу приходит параллельное ожидание действия. Но если у нас нет возможности указать фиксированное время для паузы, то применить такую конструкцию мы, увы, не сможем,  битрикс просто не даст сохранить бизнес-процесс. И это правильно, поскольку суть конструкции в том, что если ветка ожидающего действия начата — другие мгновенно закрываются. Вместо ожидания действия здесь можно применить параллельное выполнение, в котором в каждой ветке будет одновременно выполняться определенная логика, которая в случае более раннего завершения схлопнет всю конструкцию целиком, прервав остальные ветки, при помощи действия "Установить статус". Для нашего примера это будет выглядеть таким образом:

Параллельное выполнение с произвольным ожиданием действия
Параллельное выполнение с произвольным ожиданием действия

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

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

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

Заключение

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

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

Надеемся, что представленные советы и подходы будут полезны вам в работе и поспособствуют более эффективному и продуманному построению бизнес-логики в ваших проектах. Спасибо за внимание, до встречи в следующих статьях!

Комментарии (0)