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

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

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

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

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

Для реализации нам потребуются следующие объекты и методы платформы:

  1. Объект ФоновыеЗадания и его метод Выполнить().
  2. Механизм Временного хранилища для передачи данных между сеансами.
  3. Обработчик ожидания на форме для мониторинга состояния задания.

Шаг 1. Подготовка серверного метода

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

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


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

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

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

Проанализируем код запуска на стороне клиента и сервера:


&НаКлиенте
Процедура ЗапуститьОбработку(Команда)
    АдресХранилища = ПодготовитьХранилищеНаСервере();
    ИдентификаторЗадания = ЗапуститьЗаданиеНаСервере(АдресХранилища);
    
    // Подключаем обработчик ожидания, чтобы проверять готовность каждые 2 секунды
    ПодключитьОбработчикОжидания("ПроверитьСтатусЗадания", 2);
КонецПроцедуры

&НаСервере
Функция ПодготовитьХранилищеНаСервере()
    Возврат ПоместитьВоВременноеХранилище(Неопределено, УникальныйИдентификатор);
КонецФункции

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

Шаг 3. Мониторинг состояния и получение результата

Разберем подробнее, как понять, что фоновое задание завершилось успешно или с ошибкой. Для этого мы используем ранее подключенный обработчик ожидания ПроверитьСтатусЗадания. Мы должны обратиться к объекту ФоновоеЗадание по его идентификатору и проверить свойство Состояние.


&НаКлиенте
Процедура ПроверитьСтатусЗадания()
    Если ЗаданиеЗавершено(ИдентификаторЗадания) Тогда
        ОтключитьОбработчикОжидания("ПроверитьСтатусЗадания");
        ПолучитьИОбработатьРезультат();
    КонецЕсли;
КонецПроцедуры

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

Когда состояние задания становится Завершено, мы можем безопасно прочитать данные из временного хранилища. Посмотрим на пример получения данных:


&НаСервере
Процедура ПолучитьИОбработатьРезультат()
    Данные = ПолучитьИзВременногоХранилища(АдресХранилища);
    Если ТипЗнч(Данные) = Тип("ТаблицаЗначений") Тогда
        Объект.РезультатыРасчета.Загрузить(Данные);
    КонецЕсли;
КонецПроцедуры

Важные нюансы и рекомендации

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

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

2. Контекст выполнения. Фоновое задание запускается в отдельном сеансе. Это означает, что параметры сеанса могут быть не инициализированы, если в модуле сеанса не прописана соответствующая логика. Всегда проверяйте доступность необходимых глобальных переменных.

3. Обработка ошибок. Если в коде фонового задания произойдет исключение, оно не будет показано пользователю напрямую. Программа просто перейдет в состояние АварийноЗавершено. Поэтому всегда используйте блок Попытка...Исключение внутри фонового метода и логируйте ошибки или передавайте их описание через АдресХранилища.

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

Пример вызова через БСП выглядит значительно лаконичнее:


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

Таким образом, использование фоновых заданий — это мощный инструмент повышения комфорта работы пользователя. Мы рассмотрели базовый механизм платформы, который позволяет эффективно распределять нагрузку и создавать современные, быстрые приложения на базе 1С.

← На главную