Как исключить одновременное выполнение регламентного задания в 1С:Управление торговлей 10?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

В процессе автоматизации обмена данными часто возникает классическая дилемма: нам необходимо проверять наличие новых файлов в папке очень часто (например, каждые 25 секунд), однако сама обработка этих файлов может занимать значительное время (до 5-10 минут). Если не предусмотреть механизм защиты, система будет каждые 25 секунд порождать новый поток загрузки, что приведет к конфликтам доступа к файлам, перегрузке сервера и дублированию данных в базе. В рамках данной статьи мы разберем несколько профессиональных способов решения этой задачи, начиная от простых настроек платформы и заканчивая продвинутой программной логикой.

Способ 1: Использование свойства «Ключ» регламентного задания

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

Преимущества этого метода:

При программном создании фонового задания этот механизм также доступен. Рассмотрим пример кода:


ПараметрыЗадания = Новый Массив;
ПараметрыЗадания.Добавить(ПараметрыЗагрузки);
КлючЗадания = "ЗагрузкаФайловИзПапки_Основная";

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

Если в момент выполнения этого кода в системе уже работает фоновое задание с ключом "ЗагрузкаФайловИзПапки_Основная", новое задание не будет создано, что гарантирует уникальность процесса.

Способ 2: Программная проверка состояния фонового задания

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


ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("Наименование", "ИмяФоновогоЗадания");
ПараметрыОтбора.Вставить("Состояние", СостояниеФоновогоЗадания.Активно);

МассивФЗ = ФоновыеЗадания.ПолучитьФоновыеЗадания(ПараметрыОтбора);

Если МассивФЗ.Количество() > 0 Тогда
    ЗаписьЖурналаРегистрации("Загрузка файлов", УровеньЖурналаРегистрации.Предупреждение, , , "Задание уже выполняется, пропускаем итерацию.");
    Возврат;
КонецЕсли;

В данном примере мы используем объект ФоновыеЗадания.ПолучитьФоновыеЗадания. Важно помнить, что поиск по наименованию должен быть точным. Также следует учитывать, что в редких случаях задание может зависнуть в состоянии Активно, хотя фактически процесс на сервере уже завершен. Для борьбы с такими «зомби-процессами» рекомендуется добавлять проверку времени запуска: если задание активно более 1 часа (при норме в 5 минут), его можно считать проблемным.

Способ 3: Механизм переименования или переноса файлов (Очередь)

Рассмотрим ситуацию с точки зрения работы с файловой системой. Вместо того чтобы полагаться только на механизмы 1С, мы можем использовать саму логику обработки файлов для предотвращения конфликтов. Профессиональным стандартом считается архитектура с разделением на папки (Input, Processing, Error, Success).

Алгоритм работы выглядит следующим образом:

  1. Регламентное задание сканирует папку Input.
  2. При обнаружении файлов задание пытается переименовать файл или переместить его в папку Processing.
  3. Если перемещение удалось — файл берется в работу. Если файл занят другим процессом или уже перемещен — текущий поток его просто не увидит.

Посмотрим на пример реализации захвата файла:


ФайлНаДиске = Новый Файл(ПутьКФайлу);
НовоеИмя = ПутьКПапкеОбработки + ФайлНаДиске.Имя;

Попытка
    ПереместитьФайл(ПутьКФайлу, НовоеИмя);
    // Начинаем чтение и загрузку из НовоеИмя
Исключение
    // Файл занят другим потоком или недоступен
    Возврат;
КонецПопытки;

Этот метод исключает ситуацию, когда два одновременно запущенных задания начнут читать один и тот же файл. Даже если 1С запустит два потока, только один из них сможет успешно переместить файл.

Способ 4: Использование управляемых блокировок (DataLock)

Для высоконагруженных систем на платформе 8.3 (даже если используется конфигурация УТ 10) наиболее надежным способом является установка блокировки на уровне СУБД. Выясним, как это реализовать. Мы можем создать в конфигурации специальный пустой Регистр Сведений (например, БлокировкиПроцессов) и перед началом работы задания пытаться заблокировать в нем определенную запись.


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

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

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

Риски использования «Файла-флага»

Часто на форумах советуют создавать пустой файл (например, busy.txt) в начале работы и удалять его в конце. Проанализируем ситуацию: что произойдет, если на сервере внезапно отключится питание или процесс 1С аварийно завершится (Critical Error)? Файл busy.txt останется в папке навсегда, и ваше регламентное задание никогда больше не запустится без ручного вмешательства.

Если вы все же решили использовать этот метод, обязательно добавьте проверку «возраста» файла-флага:


ФайлФлаг = Новый Файл(ПутьКФлагу);
Если ФайлФлаг.Существует() Тогда
    Если (ТекущаяДата() - ФайлФлаг.ПолучитьВремяИзменения()) > 3600 Тогда
        // Флагу больше часа, скорее всего процесс завис
        УдалитьФайлы(ПутьКФлагу);
    Иначе
        Возврат; // Задание еще работает
    КонецЕсли;
КонецЕсли;

Рекомендации по оптимизации интервала

Запуск регламентного задания каждые 25 секунд в УТ 10 может создавать лишнюю нагрузку на Менеджер заданий. Рассмотрим, как сделать код более «легким»:

  1. Первым делом проверяйте наличие файлов в папке через НайтиФайлы.
  2. Если файлов нет — немедленно завершайте работу, не открывая транзакций и не создавая лишних объектов.
  3. Используйте метод со свойством Ключ как основной инструмент защиты от параллелизма.

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

← На главную