При проектировании сложных бизнес-процессов в среде 1С:Предприятие 8 разработчики часто сталкиваются с необходимостью распараллеливания задач. Типичный сценарий: мы запускаем две параллельные ветки через точку Разделения, но логика процесса такова, что выполнение задачи в одной ветке делает выполнение задачи в другой ветке бессмысленным. В этой статье мы подробно разберем, можно ли решить эту задачу исключительно средствами визуального конструктора схем и какие программные методы существуют для реализации такой логики.
Рассмотрим стандартную логику платформы. Когда бизнес-процесс доходит до точки Разделения, система создает задачи по всем исходящим веткам. Чтобы процесс пошел дальше, эти ветки должны сойтись в точке Слияния. По умолчанию точка Слияния работает по принципу AND (И): она ожидает завершения всех входящих в нее веток.
Проанализируем ситуацию, когда нам нужно поведение OR (ИЛИ). Если одна из веток выполнена с определенным результатом, мы хотим «схлопнуть» остальные ветки и двигаться дальше. К сожалению, средствами только визуального конструктора (без использования встроенного языка) реализовать это невозможно. Платформа 1С не предоставляет «галочки» или настройки в схеме, которая позволяла бы одной ветке автоматически отменять другую при слиянии.
Выясним причину такого поведения. Точки маршрута в 1С — это жесткая декларативная модель. Платформа берет на себя управление жизненным циклом задач на основе схемы. Если мы указали разделение, платформа «честно» ждет сигнала о завершении каждой созданной задачи. Автоматическая отмена параллельной задачи нарушила бы целостность схемы, так как точка слияния не получила бы управления по одной из линий.
Поэтому, если ваша бизнес-логика подразумевает, что выполнение одной задачи отменяет другую, нам придется прибегнуть к программным методам. Рассмотрим их подробнее.
Рассмотрим самый распространенный вариант. При выполнении задачи в первой ветке (например, «Подписать ответ») нам нужно найти активную задачу из второй ветки («Проверить карточку») и завершить ее программно. Это делается в обработчике события задачи ПриВыполнении или в модуле самого бизнес-процесса в обработчике точки маршрута.
Разберем пример кода, который можно разместить в модуле бизнес-процесса для точки маршрута, выполнение которой должно прервать параллельную ветку:
Процедура ПодписатьПодготовленныйОтветПриВыполнении(ТочкаМаршрутаБизнесПроцесса, Задача, Отказ)
// Получим объект бизнес-процесса
БизнесПроцессОбъект = Задача.БизнесПроцесс.ПолучитьОбъект();
// Нам нужно найти все активные задачи этого процесса,
// относящиеся к параллельной ветке "Подготовить ответ"
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗадачаИсполнителя.Ссылка КАК Ссылка
|ИЗ
| Задача.ЗадачаИсполнителя КАК ЗадачаИсполнителя
|ГДЕ
| ЗадачаИсполнителя.БизнесПроцесс = &БизнесПроцесс
| И ЗадачаИсполнителя.ТочкаМаршрута = ЗНАЧЕНИЕ(БизнесПроцесс.ПроцессПродажи.ТочкаМаршрута.ПодготовитьОтвет)
| И ЗадачаИсполнителя.Выполнена = ЛОЖЬ";
Запрос.УстановитьПараметр("БизнесПроцесс", Задача.БизнесПроцесс);
РезультатЗапроса = Запрос.Выполнить();
ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
ОбъектЗадачи = ВыборкаДетальныеЗаписи.Ссылка.ПолучитьОбъект();
// Устанавливаем пометку выполнения программно
ОбъектЗадачи.ВыполнитьЗадачу();
КонецЦикла;
КонецПроцедуры
Важно помнить: метод ВыполнитьЗадачу() приведет к тому, что управление по этой ветке дойдет до точки слияния. Если это то, что вам нужно (чтобы слияние сработало), это правильный путь.
Проанализируем альтернативный подход, который часто оказывается архитектурно чище. Вместо того чтобы рисовать две параллельные ветки на схеме, мы используем одну точку действия, но программно формируем для нее несколько задач.
Посмотрим, как это работает:
ПередСозданиемЗадач этой точки мы программно формируем две задачи для разных исполнителей.ПриЗавершении этой точки мы пишем логику: если завершена хотя бы одна задача с определенным результатом, остальные задачи этой точки должны быть помечены как выполненные или отменены, и процесс должен двигаться дальше.Этот подход позволяет избежать нагромождения линий на схеме и дает полный контроль над логикой завершения через объект ФормируемыеЗадачи.
Если условие в одной из веток является критическим (например, проверка не прошла, и весь процесс должен остановиться), мы можем использовать метод Прервать(). Рассмотрим ситуацию: если «Проверка карточки» выявила фатальную ошибку, продолжать «Подготовку ответа» нет смысла, как и сам процесс.
В этом случае в коде задачи достаточно вызвать:
БизнесПроцессОбъект = Задача.БизнесПроцесс.ПолучитьОбъект();
БизнесПроцессОбъект.Состояние = Перечисления.СостоянияБизнесПроцессов.Прерван;
БизнесПроцессОбъект.Записать();
При установке состояния Прерван все текущие задачи процесса перестают быть актуальными и исчезают из списков «Мои задачи» у исполнителей. Это самый быстрый способ «схлопнуть» все параллельные ветки одновременно.
Разберем важный технический нюанс, упомянутый опытными разработчиками. При попытке программно выполнить задачу №2 из формы или обработчика задачи №1, вы можете столкнуться с ошибкой «Объект заблокирован».
Это происходит потому, что в момент выполнения первой задачи объект бизнес-процесса уже захвачен транзакцией. Чтобы избежать этого, рассмотрите следующие стратегии:
Выполнена, чтобы не войти в бесконечную рекурсию при программном вызове ВыполнитьЗадачу().Мы выяснили, что сделать автоматическое завершение параллельной задачи средствами только схем (конструктора) невозможно. Платформа 1С требует явного управления такими сценариями через код.
Наиболее надежным и «правильным» с точки зрения архитектуры решением является использование обработчиков событий в модуле бизнес-процесса, где вы можете явно найти активные задачи по параллельным веткам и завершить их, используя метод ВыполнитьЗадачу() или изменив статус самого бизнес-процесса. Это обеспечивает гибкость, которую не может предоставить визуальный редактор, и позволяет корректно обрабатывать сложные бизнес-условия.