Как правильно запускать фоновые задания в цикле в 1С:Предприятие

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

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

Базовая реализация запуска в цикле

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


Для Каждого ТекНастройка Из МассивНастроек Цикл
    ПараметрыЗадания = Новый Массив;
    ПараметрыЗадания.Добавить(ТекНастройка.Ссылка);
    
    ФоновыеЗадания.Выполнить("МойОбщийМодуль.ВыполнитьОбработкуДанных", ПараметрыЗадания);
КонецЦикла;

На первый взгляд, такая конструкция кажется рабочей, однако при большом количестве элементов (сотни или тысячи) она может привести к критической нагрузке на сервер. Рассмотрим далее, как сделать этот процесс безопасным.

1. Управление ресурсами сервера и лимитами

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

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

2. Использование уникальных ключей для защиты от дублирования

Одной из частых проблем является повторный запуск одного и того же задания пользователем. Проанализируем параметр Ключ метода ФоновыеЗадания.Выполнить(). Этот параметр позволяет идентифицировать задание.

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


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

3. Ожидание завершения и паузы

Иногда логика требует, чтобы основная процедура дождалась выполнения всех фоновых задач, прежде чем продолжить (например, для формирования итогового отчета). Для этого воспользуемся методом ФоновыеЗадания.ОжидатьЗавершения(). Посмотрим на пример, как собрать массив запущенных заданий и дождаться их окончания.


МассивЗаданий = Новый Массив;
Для Каждого ТекНастройка Из МассивНастроек Цикл
    Задание = ФоновыеЗадания.Выполнить("МойОбщийМодуль.ВыполнитьОбработкуДанных", ПараметрыЗадания);
    МассивЗаданий.Добавить(Задание);
КонецЦикла;

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

4. Обработка ошибок внутри фонового задания

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

Информацию об ошибках следует записывать либо в стандартный Журнал регистрации, либо (что более удобно для администратора системы) в специальный реквизит справочника-параметра (например, ДатаПоследнейОшибки и ТекстОшибки). Это позволит оперативно понять, почему конкретный элемент из списка не был обработан.

5. Передача контекста и работа с данными

Важно помнить техническое ограничение: фоновое задание не наследует контекст основного сеанса. Оно не видит созданные вами временные таблицы или глобальные переменные. Разберем правила передачи данных:

6. Лицензирование и транзакции

Проанализируем еще два важных момента: лицензии и транзакции. Каждое фоновое задание может занимать отдельный сеанс (и, соответственно, лицензию), особенно на старых версиях платформы или при использовании аппаратных ключей. Если у вас в справочнике 100 элементов и вы запустите 100 заданий одновременно, вы можете столкнуться с ошибкой "Превышено количество доступных лицензий".

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

Резюме по реализации

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

  1. Всегда ограничивайте количество одновременно работающих потоков.
  2. Используйте параметр Ключ для предотвращения дублей.
  3. Обязательно логируйте ошибки внутри фоновых процедур в базу данных или журнал регистрации.
  4. Минимизируйте объем данных, передаваемых в параметры задания, используя только ссылки.

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

← На главную