Как правильно реализовать выполнение длительных операций через фоновые задания в 1С 8.3

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

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

Постановка задачи и выбор метода решения

Представим ситуацию: нам необходимо обработать 100 000 строк в документе. Если запустить этот процесс непосредственно в обработчике команды на сервере, клиентское приложение будет заблокировано до окончания выполнения. Проанализируем, как этого избежать. Мы воспользуемся объектом ФоновыеЗаданияМенеджер, который позволяет инициировать выполнение процедуры в отдельном сеансе на сервере. Это позволит пользователю продолжать работу в программе или видеть индикатор прогресса, пока система выполняет расчеты.

Шаг 1. Подготовка процедуры для фонового выполнения

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

Рассмотрим пример кода для общего модуля ДлительныеОперацииСервер:


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

Шаг 2. Запуск фонового задания из управляемой формы

Теперь разберем, как инициировать этот процесс. Нам понадобится уникальный идентификатор формы, чтобы временное хранилище "жило" до момента окончания работы задания. Мы используем метод ФоновыеЗадания.Выполнить(). Выясним, какие параметры необходимы для успешного старта:

  1. Имя экспортной процедуры в формате "ИмяОбщегоМодуля.ИмяПроцедуры".
  2. Массив параметров, которые будут переданы в процедуру.
  3. Ключ задания (необязательно, но полезно для контроля уникальности).
  4. Наименование задания для отображения в консоли кластера.

Посмотрим на пример кода в модуле управляемой формы:


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

Шаг 3. Обработка ожидания и получение результата

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

Для проверки состояния задания используем объект ФоновоеЗадание и его свойство Состояние. Рассмотрим пример реализации проверки на сервере:


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

На клиенте мы продолжаем опрашивать сервер, пока функция не вернет Истина. После этого необходимо извлечь данные из временного хранилища, используя ПолучитьИзВременногоХранилища(АдресРезультата). Обратите внимание, что после получения результата обработчик ожидания необходимо отключить с помощью ОтключитьОбработчикОжидания.

Важные технические нюансы

Проанализируем несколько критических моментов, которые часто упускают разработчики:

  1. Передача данных: Не пытайтесь передать в фоновое задание ссылки на объекты, которые могут быть заблокированы. Лучше передавать простые типы или структуры данных.
  2. Контекст: Фоновое задание выполняется в отдельном сеансе. Это значит, что параметры сеанса и временные таблицы БД, созданные в основном сеансе, там не будут доступны.
  3. Лимиты: Слишком большое количество одновременно запущенных фоновых заданий может перегрузить рабочий процесс сервера rphost. Рекомендуется ограничивать количество потоков.
  4. Транзакции: Если фоновое задание падает с ошибкой, транзакция внутри него откатывается автоматически, но это не влияет на основной сеанс пользователя.

Выясним причину, по которой иногда АдресРезультата оказывается пустым. Обычно это происходит, если УникальныйИдентификатор формы не был передан при помещении во временное хранилище, и данные были удалены системой при смене серверного вызова. Всегда связывайте хранилище с формой или самим фоновым заданием.

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

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

← На главную