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

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

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

Зачем использовать фоновые задания?

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

  1. Отзывчивость интерфейса: Пользователь может продолжать работу в других окнах системы, пока идет расчет.
  2. Стабильность соединения: Длительные операции в фоне менее чувствительны к кратковременным разрывам связи между клиентом и сервером.
  3. Контроль выполнения: Мы можем в любой момент прервать фоновое задание или вывести индикатор прогресса (ProgressBar).

Шаг 1. Подготовка серверной процедуры

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

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


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

Шаг 2. Запуск задания из формы (Клиент)

Теперь перейдем к реализации запуска на стороне клиента. Нам потребуется уникальный идентификатор формы, чтобы временное хранилище "жило" до момента окончания работы задания. Выясним причину использования УникальныйИдентификатор: он связывает данные в хранилище с конкретным сеансом и окном пользователя.

Проанализируем программный код запуска:


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

На стороне сервера (в модуле формы) функция запуска будет выглядеть следующим образом:


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

Шаг 3. Отслеживание прогресса и завершения

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


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

Разберем подробнее, как проверить состояние объекта ФоновоеЗадание на сервере. Мы используем метод НайтиПоУникальномуИдентификатору:


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

Важные нюансы и советы

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

Использование метода ФоновыеЗадания.СообщитьПрогресс позволяет сделать интерфейс еще более дружелюбным. На клиенте вы можете считывать это значение через свойство задания Прогресс и обновлять индикатор на форме. Это особенно полезно, когда операция длится более 30 секунд.

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

← На главную