Запуск бизнес-процесса из кода: создание, точки старта и ошибки
Содержание
Чтобы программно стартовать бизнес-процесс в 1С, на сервере создайте объект через БизнесПроцессы.<Имя>.СоздатьБизнесПроцесс(), заполните реквизиты, запишите его и вызовите метод Старт(). После этого платформа ставит процесс в точку старта карты маршрута, проходит маршрут до первой точки действия и создаёт задачи исполнителям.
Есть два рабочих варианта. Первый — создать и запустить процесс в одном серверном вызове: подходит для кнопок «Отправить на согласование» и обработчиков проведения. Второй — сначала записать процесс, а стартовать позже: по расписанию, после проверки или пакетом в фоновом задании. Ниже разбираем оба, а также точки старта, права, ошибки и массовый запуск.
Как устроен бизнес-процесс и откуда его можно запустить
Бизнес-процесс в конфигурации — это объект метаданных со своей картой маршрута. Карта состоит из точек: Старт, Действие, Условие, Выбор варианта, Разделение, Слияние, Обработка, Вложенный бизнес-процесс, Завершение. Работа людей идёт через связанный объект Задача: каждая точка действия порождает задачи.
Объект бизнес-процесса живёт в трёх состояниях:
- 📝 записан, не стартован — флаг
Стартован = Ложь, задач ещё нет; - ▶️ стартован —
Стартован = Истина, по маршруту созданы задачи; - ✅ завершён —
Завершен = Истина, процесс дошёл до точки завершения.
Программный старт — это перевод из первого состояния во второе. Вызвать его можно из разных мест:
| Откуда запускаем | Где выполняется код | Типичный сценарий |
|---|---|---|
| Команда формы документа | Серверная процедура общего модуля или модуля формы &НаСервере | «Отправить договор на согласование» |
| Обработка проведения документа | Модуль объекта документа | Автостарт проверки после проведения |
| Регламентное задание | Процедура общего модуля | Ежедневный старт отложенных процессов |
| Фоновое задание | Процедура общего модуля | Массовый запуск сотен процессов |
| HTTP-сервис, обмен | Модуль сервиса или обработчик обмена | Запуск по событию из внешней системы |
| Точка «Вложенный бизнес-процесс» | Платформа сама | Подпроцесс внутри основного маршрута |
Старт() — метод объекта, а объекты бизнес-процессов доступны только на сервере. С клиента вызывайте серверную функцию и передавайте в неё ссылки, а не объекты.
Метод Старт(): создать и запустить процесс за один вызов
Самый частый случай: пользователь нажал кнопку, процесс должен уйти в работу сразу. Код удобно держать в серверном общем модуле, чтобы его вызывали и формы, и регламентные задания.
// Общий модуль СогласованиеСервер (Сервер, Вызов сервера)
Функция СтартоватьСогласование(Предмет, Исполнитель, Комментарий = "") Экспорт
БП = БизнесПроцессы.Согласование.СоздатьБизнесПроцесс();
БП.Дата = ТекущаяДатаСеанса();
БП.Предмет = Предмет;
БП.Исполнитель = Исполнитель;
БП.Описание = Комментарий;
БП.Автор = Пользователи.ТекущийПользователь();
НачатьТранзакцию();
Попытка
БП.Записать();
БП.Старт();
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
Возврат БП.Ссылка;
КонецФункции
Что здесь происходит по шагам:
СоздатьБизнесПроцесс()возвращает новый объект в памяти. В базе его ещё нет.- Реквизиты заполняются так же, как у документа. Названия
Предмет,Исполнитель,Описаниевзяты для примера — у вас будут реквизиты вашего бизнес-процесса. Записать()сохраняет объект и выдаёт ему ссылку и номер.Старт()переводит процесс в точку старта и прогоняет маршрут до первой точки действия. На этом этапе срабатывают обработчики точек карты, и создаются задачи.- Транзакция объединяет запись и старт: если старт упал, в базе не останется «висящего» записанного, но не стартованного процесса.
Пользователи.ТекущийПользователь() — функция Библиотеки стандартных подсистем. Если конфигурация собрана без БСП, заполняйте автора своим способом.
Вызов с клиента выглядит так:
&НаКлиенте
Процедура ОтправитьНаСогласование(Команда)
Ссылка = СогласованиеСервер.СтартоватьСогласование(Объект.Ссылка, Исполнитель);
ПоказатьОповещениеПользователя("Согласование запущено", ПолучитьНавигационнуюСсылку(Ссылка));
КонецПроцедуры
Перед вызовом документ должен быть записан: в процесс уходит ссылка, а у нового объекта формы она пустая.
Раздельное создание и отложенный запуск процесса
Иногда процесс нужно подготовить заранее, а запустить позже. Например, менеджер собирает маршрут согласования, а старт происходит в 9:00 следующего дня или после оплаты счёта.
В объектной модели платформы для этого нет отдельного метода «Запустить» — запуск всегда делает Старт(). Процедуры с названиями вроде «ЗапуститьПроцесс» в типовых конфигурациях — это обёртки поверх него. Схема раздельного запуска такая:
- Создайте и запишите процесс через
Записать(), не вызываяСтарт(). - Сохраните условие запуска: дату в реквизите процесса или запись в своём регистре сведений.
- В момент запуска получите объект по ссылке, проверьте флаг и стартуйте.
Процедура СтартоватьПодготовленный(СсылкаБП) Экспорт
БП = СсылкаБП.ПолучитьОбъект();
Если БП.Стартован Тогда
Возврат; // повторный старт не нужен и вызовет ошибку
КонецЕсли;
Если БП.ПометкаУдаления Тогда
Возврат;
КонецЕсли;
БП.Заблокировать();
БП.Старт();
КонецПроцедуры
Заблокировать() ставит объектную блокировку. Если процесс в эту секунду открыт пользователем на редактирование, вызов выдаст исключение, и вы не стартуете то, что человек ещё правит.
Найти подготовленные, но не запущенные процессы помогает запрос:
Запрос = Новый Запрос(
"ВЫБРАТЬ
| БП.Ссылка КАК Ссылка
|ИЗ
| БизнесПроцесс.Согласование КАК БП
|ГДЕ
| НЕ БП.Стартован
| И НЕ БП.ПометкаУдаления
| И БП.Дата <= &ТекущаяДата");
Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса());
В Библиотеке стандартных подсистем есть подсистема «Бизнес-процессы и задачи» с механизмом отложенного старта для её процессов. Если ваш процесс на ней построен, используйте штатный механизм, а не пишите свой регламент.
Точка старта и параметры запуска
У Старт() есть необязательный параметр — точка старта. Он нужен, когда на карте маршрута несколько точек Старт. Например, «Согласование» может начинаться с юриста для договоров и сразу с бухгалтера для счетов.
Ссылку на точку берут из менеджера по имени точки на карте:
Если ТипЗнч(Предмет) = Тип("ДокументСсылка.Договор") Тогда
Точка = БизнесПроцессы.Согласование.ТочкиМаршрута.СтартЮрист;
Иначе
Точка = БизнесПроцессы.Согласование.ТочкиМаршрута.СтартБухгалтер;
КонецЕсли;
БП.Записать();
БП.Старт(Точка);
Если точек старта несколько, а параметр не передан, запуск не пойдёт по нужной ветке. Передавайте точку явно всегда, когда стартов больше одного.
Как передать данные внутрь маршрута
Прямой передачи параметров в Старт() нет. Всё, что нужно маршруту, кладите в реквизиты и табличные части бизнес-процесса до записи:
- 👤 исполнителей и роли — в реквизиты процесса, их читают обработчики точек действия при создании задач;
- 📎 предмет (документ, договор, контрагент) — в реквизит ссылочного типа;
- 📋 список согласующих — в табличную часть, если согласование идёт по очереди или параллельно;
- 🗓 срок — в реквизит даты, из него задачам ставится срок исполнения.
Обработчики точки действия (ПередСозданиемЗадач, ПриСозданииЗадач) берут эти значения и заполняют задачи. Условие на точке Условие читает их в обработчике ПроверкаУсловия. Поэтому порядок жёсткий: сначала заполнить всё, потом стартовать. Изменение реквизита после старта не перестроит уже созданные задачи.
Права и привилегированный режим
У бизнес-процесса в роли есть отдельные права на старт: Старт для программного запуска и Интерактивный старт для запуска из формы. Если у пользователя нет права Старт, вызов метода из кода упадёт с ошибкой нарушения прав, даже если записывать процесс он может.
Варианты решения:
| Способ | Когда подходит | Риск |
|---|---|---|
Выдать право Старт в роли пользователя | Пользователь сам инициирует процесс | Он сможет стартовать и другие процессы этого вида |
УстановитьПривилегированныйРежим(Истина) в серверной процедуре | Старт — служебное следствие действия, например проведения | Проверки прав пропускаются — контроль делайте в коде сами |
| Старт в регламентном задании от служебного пользователя | Отложенный и массовый запуск | Автором процесса станет служебный пользователь — заполняйте автора явно |
Привилегированный режим включайте только в серверном общем модуле и на минимальный участок кода. Не выносите его в процедуру с параметрами, которую можно вызвать с клиента с произвольными данными.
Обработка ошибок при старте
Ошибки при запуске делятся на четыре группы. Их легко узнать по моменту, когда они возникают.
Ошибка в обработчике точки — самая коварная. Старт проходит маршрут сразу, поэтому исключение в условии или в создании задач откатывает весь старт. Пользователь видит сообщение об ошибке, а не о маршруте.
Шаблон с записью в журнал регистрации:
Попытка
СтартоватьПодготовленный(СсылкаБП);
Исключение
ТекстОшибки = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
ЗаписьЖурналаРегистрации("Бизнес-процессы.Старт",
УровеньЖурналаРегистрации.Ошибка,
Метаданные.БизнесПроцессы.Согласование,
СсылкаБП,
ТекстОшибки);
КонецПопытки;
На свежих версиях платформы вместо ПодробноеПредставлениеОшибки рекомендуется ОбработкаОшибок.ПодробноеПредставлениеОшибки. Старый вариант работает, но синтакс-помощник помечает его как устаревший.
Если старт идёт внутри внешней транзакции, правило такое: перехватили исключение — значит, транзакцию надо отменить и пробросить ошибку дальше через ВызватьИсключение. Иначе внешний код продолжит работу в транзакции, которая уже не может быть зафиксирована.
Массовый запуск бизнес-процессов и скорость
Когда нужно стартовать сотни процессов — например, годовую сверку по 400 контрагентам — запуск одним циклом в одной транзакции плох по трём причинам:
- 🔒 транзакция держит блокировки на всё время цикла, и другие пользователи ждут;
- 💥 одна ошибка откатывает все 400 стартов;
- ⏳ интерфейс пользователя висит до конца цикла.
Рабочая схема:
- Отдельная транзакция на каждый процесс: запись и старт одного процесса — одна транзакция. Ошибка затрагивает только его.
- Запуск в фоне через
ФоновыеЗадания.Выполнить("ОбщийМодуль.Процедура", Параметры). Пользователь получает управление сразу. - Порции. Если процессов тысячи, делите список на части, например по 100–200 штук, и запускайте несколько фоновых заданий. Параллельно — только если процессы не пишут в одни и те же данные, иначе получите ожидания на блокировках.
- Итог в журнал или регистр: сколько стартовало, сколько упало и почему.
Процедура СтартоватьПакет(МассивПредметов, Исполнитель) Экспорт
Успешно = 0;
Ошибок = 0;
Для Каждого Предмет Из МассивПредметов Цикл
Попытка
СогласованиеСервер.СтартоватьСогласование(Предмет, Исполнитель);
Успешно = Успешно + 1;
Исключение
Ошибок = Ошибок + 1;
ЗаписьЖурналаРегистрации("Бизнес-процессы.Массовый старт",
УровеньЖурналаРегистрации.Ошибка, , Предмет,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецЦикла;
ЗаписьЖурналаРегистрации("Бизнес-процессы.Массовый старт",
УровеньЖурналаРегистрации.Информация, , ,
СтрШаблон("Стартовано: %1, ошибок: %2", Успешно, Ошибок));
КонецПроцедуры
Функция СтартоватьСогласование из первого примера уже открывает свою транзакцию. Поэтому цикл здесь транзакцию не открывает, и одна ошибка не задевает остальные процессы.
Что ещё ускоряет массовый старт:
- ⚡ тяжёлые запросы в обработчиках точек выполняйте один раз до цикла и передавайте результат в реквизиты процесса;
- ⚡ не открывайте форму и не вызывайте клиентские оповещения из фонового задания;
- ⚡ отключайте лишние подписки на события на время пакета только если точно понимаете их назначение — иначе потеряете связанные данные.