Почему фоновое задание ОбновитьСведенияОСогласииВФоне блокирует документы при проведении в 1С:ЗУП 3?

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

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

Проанализируем, почему возникает эта проблема, как устроена работа подсистемы СЭДО СФР и какими способами можно исключить блокировку объектов при массовой загрузке.

Анализ проблемы: как работает механизм ожидания фиксации транзакции

Рассмотрим логику автора вопроса. При записи кадрового документа срабатывает типовая подписка на событие ПриЗаписиОтзываСогласия, которая вызывает процедуры общего модуля СЭДОФССРасширенный. В рамках подсистемы стартует фоновое задание ОбновитьСведенияОСогласииВФоне.

Чтобы фоновое задание не прочитало незафиксированные данные из сеанса записи, в нем вызывается специальная сервисная функция (например, ДождатьсяОкончанияЗаписиОбъекта). Для синхронизации фоновое задание открывает собственную транзакцию и пытается наложить управляемую блокировку на ссылку документа:


НачатьТранзакцию();
Попытка
    Блокировка = Новый БлокировкаДанных;
    ЭлементБлокировки = Блокировка.Добавить(ОбъектМетаданных.ПолноеИмя());
    ЭлементБлокировки.УстановитьЗначение("Ссылка", Ссылка);
    Блокировка.Заблокировать();
    ОтменитьТранзакцию();
Исключение
    ОтменитьТранзакцию();
    // Обработка таймаута ожидания
КонецПопытки;

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

  1. В первом цикле документ просто записывается методом Док.Записать(). В этот момент инициируется фоновое задание.
  2. Основной сеанс не ждет фонового процесса, завершает цикл записи и сразу переходит ко второму циклу, вызывая Док.Записать(РежимЗаписиДокумента.Проведение).
  3. В этот момент фоновое задание либо накладывает управляемую блокировку для контроля фиксации, либо выполняет собственную транзакцию обновления связанных регистров сведений по согласиям СЭДО.
  4. Попытка проведения наталкивается на блокировку, установленную фоновым заданием, и по истечении таймаута ожидания (по умолчанию 20 секунд) завершается исключением. Документ остается непроведенным.

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

Способ 1. Использование режима загрузки данных (ОбменДанными.Загрузка = Истина)

Разберем самый эффективный и правильный способ решения проблемы при интеграциях и пакетных обменах. Платформа 1С:Предприятие предоставляет штатный механизм отключения сервисных обработчиков через свойство ОбменДанными.Загрузка.

Если перед записью и проведением установить это свойство в значение Истина, платформенные и прикладные подписки на события (включая запуск фоновых обновлений согласий СЭДО) выполняться не будут:


Для Каждого Док Из Доки Цикл
    // Заполнение реквизитов документа
    Док.ОбменДанными.Загрузка = Истина;
    Попытка
        Док.Записать(РежимЗаписиДокумента.Проведение);
    Исключение
        ЗаписьЖурналаРегистрации("Ошибка проведения документа",
            УровеньЖурналаРегистрации.Ошибка,,,
            ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

Важно: режим Загрузка = Истина отключает большинство прикладных проверок заполнения. Убедитесь, что все необходимые реквизиты документа корректно заполнены до вызова записи.

Способ 2. Совмещение записи и проведения в одну операцию

Проанализируем архитектурную ошибку исходного алгоритма. Разделение записи и проведения на два разных цикла без паузы гарантированно порождает гонку процессов между основным сеансом и фоновым заданием.

Если по условиям бизнес-логики отключать подписки через ОбменДанными.Загрузка нельзя, следует исключить промежуточную запись без проведения. Выполним проведение сразу в первом цикле:


Для Каждого Док Из Доки Цикл
    // Заполнение реквизитов документа
    Попытка
        Док.Записать(РежимЗаписиДокумента.Проведение);
    Исключение
        ЗаписьЖурналаРегистрации("Ошибка проведения документа",
            УровеньЖурналаРегистрации.Ошибка,,,
            ОписаниеОшибки());
    КонецПопытки;
КонецЦикла;

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

Способ 3. Пакетная обработка порциями и явное ожидание завершения заданий

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

  1. Обрабатываем массив документов небольшими порциями (пачками по 50–100 штук), чтобы не создавать лавинообразную нагрузку на планировщик фоновых заданий.
  2. Если фоновые задания запускаются программно с сохранением ссылок на них, вызываем метод ФоновыеЗадания.ОжидатьЗавершения(МассивЗаданий, Таймаут) перед переходом к блоку проведения.
  3. Если фоновые задания создаются неявно подписками, используем паузы или анализ журнала регистрации для контроля завершения сопутствующих процедур перед массовым проведением.

Также перед проведением массовых обновлений кадровой информации рекомендуется временно приостанавливать регламентные задания по СЭДО/СФР, выполняя актуализацию сведений групповой регламентной обработкой уже после завершения основного импорта данных.

← На главную