Как исключить одновременное выполнение регламентного задания и предотвратить появление дублей

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

В процессе эксплуатации высоконагруженных систем на базе 1С:Предприятие 8.3 часто возникает ситуация, когда одно и то же регламентное задание запускается параллельно в нескольких экземплярах. Это может произойти по расписанию, либо если пользователь инициирует выполнение вручную, не дождавшись завершения фонового процесса. Результатом такой «гонки» часто становятся дублирующиеся документы, элементы справочников или некорректные остатки в регистрах. В этой статье мы подробно разберем, как обеспечить строго последовательное выполнение заданий и защитить базу данных от логических ошибок.

Использование штатного механизма «Ключ» регламентного задания

Рассмотрим самый простой и эффективный способ, заложенный в саму платформу 1С. У объекта РегламентноеЗадание существует свойство Ключ. Проанализируем, как оно работает: платформа гарантирует, что в один момент времени может выполняться только одно задание с конкретным ключом для данного объекта метаданных. Если система пытается запустить второе задание с тем же ключом, запуск просто не произойдет.

Разберем по шагам, как настроить этот механизм в пользовательском режиме (на примере УТ 11 или любой конфигурации на БСП):

  1. Перейдем в раздел Обслуживание — Регламентные и фоновые задания.
  2. Найдем нужное нам задание в списке и откроем его карточку.
  3. В поле Ключ введем произвольную уникальную строку (например, «УникальныйКлючОбработкиДанных»).
  4. Сохраним настройки.

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

Программная установка ключа при запуске фонового задания

Если мы запускаем фоновое задание не через расписание, а программно из кода (например, при нажатии кнопки в обработке), нам следует использовать параметры метода Выполнить менеджера фоновых заданий. Рассмотрим пример кода, который предотвращает параллельный запуск:


ПараметрыЗапуска = Новый Массив;
ПараметрыЗапуска.Добавить(ПараметрыОбработки);

// Указываем уникальный ключ для контроля параллельности
КлючЗадания = "ЗагрузкаДанныхИзВнешнейСистемы";

// Пытаемся запустить фоновое задание
Задание = ФоновыеЗадания.Выполнить("МойМодуль.ВыполнитьЗагрузку", ПараметрыЗапуска, КлючЗадания, "Загрузка данных");

В данном случае, если в системе уже есть активное фоновое задание с текстом КлючЗадания, платформа выдаст исключение или не создаст новое задание (в зависимости от контекста). Это позволяет нам нативно контролировать очередь выполнения.

Использование инструментов БСП для контроля выполнения

В современных конфигурациях (УТ, ERP, КА) рекомендуется использовать механизмы Библиотеки стандартных подсистем. Выясним, как правильно интегрировать проверку в начало процедуры регламентного задания. Рассмотрим использование метода ПриНачалеВыполненияРегламентногоЗадания.

Добавим в начало программного кода задания следующий вызов:


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

Этот метод не только проверяет «зависание» задания, но и корректно обрабатывает ситуации, когда база данных является копией, предотвращая нежелательную отправку писем или обмен данными из тестовой среды.

Проверка состояния через менеджер регламентных заданий

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


Функция РегламентноеЗаданиеВыполняется(UUIDЗадания) Экспорт
    РегламентноеЗадание = РегламентныеЗадания.ПолучитьРегламентноеЗадание(UUIDЗадания);
    
    Если РегламентноеЗадание <> Неопределено Тогда
        Возврат РегламентноеЗадание.Выполняется;
    Иначе
        Возврат Ложь;
    КонецЕсли;
КонецФункции

Важно помнить, что свойство Выполняется возвращает Истина только в том случае, если в консоли кластера 1С действительно активен сеанс фонового задания. Если произошел аварийный сбой рабочего процесса, статус может обновиться не сразу.

Метод управляемых блокировок для максимальной надежности

Рассмотрим ситуацию, когда стандартных средств недостаточно (например, при работе в распределенных кластерах). Самый надежный способ гарантировать уникальность процесса — использование объекта БлокировкаДанных. Мы можем заблокировать «виртуальный» ресурс в начале транзакции.


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

Преимущество этого метода: даже если платформа по какой-то причине запустит два сеанса, второй сеанс просто не сможет установить блокировку и будет ждать завершения первого (или завершится по таймауту), что гарантированно исключит создание дублей.

Почему создаются дубли, даже если проверка есть?

Проанализируем интересную особенность, упомянутую опытными разработчиками. Бывают случаи, когда программист запустил 1С в режиме отладки с параметром /C РежимОтладки и нажал кнопку Выполнить не в фоне. В этом случае код выполняется в контексте клиентского сеанса, а не фонового задания. Платформенная проверка свойства Ключ при этом не срабатывает, так как с точки зрения сервера это обычный вызов серверного метода пользователем.

Чтобы защититься от таких ситуаций, рекомендуем всегда внедрять в код логику идемпотентности. Перед созданием любого нового объекта (документа, контрагента) всегда делайте проверку на его существование по уникальным полям (например, по идентификатору из внешней системы или комбинации даты, номера и суммы). Это — «последний рубеж» обороны, который спасет ваши данные, даже если все остальные механизмы контроля запуска будут обойдены.

Подведем итоги

Для обеспечения последовательного выполнения заданий мы рекомендуем комбинированный подход:

  1. Всегда устанавливайте Ключ в настройках регламентного задания.
  2. Используйте стандартные вызовы БСП для проверки контекста выполнения.
  3. Проектируйте алгоритмы так, чтобы они проверяли наличие созданных данных перед записью новых (принцип идемпотентности).
  4. При необходимости жесткого контроля используйте управляемые блокировки в транзакции.

Применяя эти правила, мы обеспечим стабильную работу системы и целостность данных в любых режимах эксплуатации.

← На главную