Как запустить бизнес-процесс строго после проведения документа в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Довольно часто в прикладных решениях 1С возникает задача инициализации бизнес-процесса на основании созданного или измененного документа. Типичная ошибка начинающих разработчиков — прямой вызов метода БизнесПроцесс.Старт() непосредственно в процедуре ОбработкаПроведения модуля объекта или в подписке на событие ОбработкаПроведения / ПриЗаписи.

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

Почему нельзя стартовать бизнес-процесс прямо в ОбработкеПроведения?

Проанализируем механику работы транзакций в платформе 1С:

  1. Процедура ОбработкаПроведения всегда исполняется внутри неявной транзакции записи документа.
  2. Метод Старт() бизнес-процесса работает синхронно: он сразу создает свои записи в таблицах базы данных, формирует задачи и продвигает маршрут. Если на первой точке маршрута есть программные обработчики, они также выполняются немедленно.
  3. Пока весь стартовый алгоритм бизнес-процесса не завершится, транзакция проведения документа остается открытой. Это надолго блокирует данные документа и связанные регистры, увеличивая риск взаимоблокировок (deadlocks).
  4. Если при старте бизнес-процесса произойдет ошибка, будет отменено и проведение исходного документа. Наоборот, если процесс стартовал, а на выходе из проведения возникнет исключение — возникнет противоречивое состояние данных.
  5. При групповом перепроведении документов синхронный запуск приведет к лавинообразному созданию сотен процессов и зависанию системы.

Рассмотрим проверенные и архитектурно правильные способы решения этой задачи.

Способ 1. Запуск через фоновое задание (отложенный старт транзакции)

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

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

Разберем по шагам реализацию данного механизма. В общем модуле (например, БизнесПроцессыСервер с установленным флагом Вызов сервера) создадим экспортную процедуру:


Процедура ЗапуститьПроцессПоДокументу(ПараметрыЗапуска) Экспорт
    ДокументСсылка = ПараметрыЗапуска.СсылкаНаДокумент;
    
    // Создаем и заполняем бизнес-процесс
    НовыйПроцесс = БизнесПроцессы.Согласование.СоздатьБизнесПроцесс();
    НовыйПроцесс.Дата = ТекущаяДатаСеанса();
    НовыйПроцесс.Предмет = ДокументСсылка;
    НовыйПроцесс.Записать();
    
    // Запускаем процесс
    НовыйПроцесс.Старт();
КонецПроцедуры

Теперь в модуле объекта документа в процедуре ОбработкаПроведения инициируем фоновое задание:


Процедура ОбработкаПроведения(Отказ, РежимПроведения)
    // Основные движения документа по регистрам
    // ...
    
    // Подготавливаем параметры и вызываем фоновое задание
    ПараметрыЗадания = Новый Структура;
    ПараметрыЗадания.Вставить("СсылкаНаДокумент", ЭтотОбъект.Ссылка);
    
    МассивПараметров = Новый Массив;
    МассивПараметров.Добавить(ПараметрыЗадания);
    
    ФоновыеЗадания.Выполнить("БизнесПроцессыСервер.ЗапуститьПроцессПоДокументу", МассивПараметров);
КонецПроцедуры

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

Способ 2. Архитектура очереди через независимый регистр сведений

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

  1. Создаем независимый непериодический регистр сведений ОчередьЗапускаБизнесПроцессов с измерением Документ (тип: ДокументСсылка) и ресурсом ДатаПостановки (тип: Дата).
  2. В процедуре ОбработкаПроведения (или в подписке на событие ПриЗаписи проведенного документа) быстро фиксируем ссылку на документ в регистре:

МенеджерЗаписи = РегистрыСведений.ОчередьЗапускаБизнесПроцессов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Документ = ЭтотОбъект.Ссылка;
МенеджерЗаписи.ДатаПостановки = ТекущаяДатаСеанса();
МенеджерЗаписи.Записать(Истина);
  1. Создаем регламентное задание, которое запускается по расписанию (например, каждые 30–60 секунд). Регламентное задание порциями считывает записи из регистра, запускает соответствующие бизнес-процессы и удаляет обработанные строки.

Процедура ОбработатьОчередьЗапуска() Экспорт
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ ПЕРВЫЕ 50
        |	Очередь.Документ КАК Документ
        |ИЗ
        |	РегистрСведений.ОчередьЗапускаБизнесПроцессов КАК Очередь
        |УПОРЯДОЧИТЬ ПО
        |	Очередь.ДатаПостановки ВОЗР";
    
    Выборка = Запрос.Выполнить().Выбрать();
    Пока Выборка.Следующий() Цикл
        Блокировка = Новый БлокировкаДанных;
        ЭлементБлокировки = Блокировка.Добавить("РегистрСведений.ОчередьЗапускаБизнесПроцессов");
        ЭлементБлокировки.УстановитьЗначение("Документ", Выборка.Документ);
        
        НачатьТранзакцию();
        Попытка
            Блокировка.Заблокировать();
            
            // Запуск бизнес-процесса
            НовыйПроцесс = БизнесПроцессы.Согласование.СоздатьБизнесПроцесс();
            НовыйПроцесс.Предмет = Выборка.Документ;
            НовыйПроцесс.Записать();
            НовыйПроцесс.Старт();
            
            // Удаление из очереди
            МенеджерЗаписи = РегистрыСведений.ОчередьЗапускаБизнесПроцессов.СоздатьМенеджерЗаписи();
            МенеджерЗаписи.Документ = Выборка.Документ;
            МенеджерЗаписи.Удалить();
            
            ЗафиксироватьТранзакцию();
        Исключение
            ОтменитьТранзакцию();
            // Запись ошибки в Журнал Регистрации
        КонецПопытки;
    КонецЦикла;
КонецПроцедуры

Способ 3. Отложенный запуск из формы документа (обработчик ожидания)

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

В модуле управляемой формы используем комбинацию событий ПослеЗаписиНаСервере и ПодключитьОбработчикОжидания:


&НаСервере
Процедура ПослеЗаписиНаСервере(Отказ, ТекущийОбъект, ПараметрыЗаписи)
    // Проверяем, что документ успешно проведен
    Если ТекущийОбъект.Проведен И ПараметрыЗаписи.РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
        ПараметрыФормы = Новый Структура("ТребуетсяСтартПроцесса", Истина);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПослеЗаписи(ПараметрыЗаписи)
    Если ПараметрыЗаписи.Свойство("ТребуетсяСтартПроцесса") Тогда
        // Подключаем однократный обработчик с минимальной задержкой
        ПодключитьОбработчикОжидания("ВыполнитьОтложенныйСтартБизнесПроцесса", 0.1, Истина);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьОтложенныйСтартБизнесПроцесса()
    СтартоватьПроцессНаСервере(Объект.Ссылка);
КонецПроцедуры

&НаСервереБезКонтекста
Процедура СтартоватьПроцессНаСервере(СсылкаНаДокумент)
    НовыйПроцесс = БизнесПроцессы.Согласование.СоздатьБизнесПроцесс();
    НовыйПроцесс.Предмет = СсылкаНаДокумент;
    НовыйПроцесс.Записать();
    НовыйПроцесс.Старт();
КонецПроцедуры

Ограничение: этот подход не сработает при программном проведении документа через внешние обработки, загрузки или обмен данными, так как форма при этом не открывается.

Итоги и рекомендации

Выбор оптимального способа зависит от контекста вашей системы:

  1. Для типовых серверных конфигураций с невысокой интенсивностью групповых операций проще всего использовать фоновые задания.
  2. Для высоконагруженных систем с частым перепроведением документов лучшим выбором является архитектура очереди через регламентное задание.
  3. Если конфигурация построена на базе БСП («1С:Документооборот», «1С:ERP»), рекомендуется использовать встроенную подсистему Бизнес-события, которая автоматически берет на себя асинхронную маршрутизацию процессов.
← На главную