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