В современной разработке на платформе 1С:Предприятие 8.3 использование фоновых заданий является стандартом де-факто для выполнения длительных операций, таких как формирование тяжелых отчетов, интеграция с внешними системами или массовая обработка данных. Это позволяет не блокировать интерфейс пользователя и повышает общую отзывчивость системы. В данной статье мы детально разберем, как программно запускать фоновые задания, передавать в них данные и корректно получать результат выполнения.
Фоновое задание — это объект платформы, который позволяет выполнить процедуру общего модуля в отдельном сеансе на стороне сервера. Проанализируем основные преимущества такого подхода: во-первых, пользователь может продолжать работу, пока сервер выполняет расчеты; во-вторых, на многопроцессорных системах это позволяет распараллеливать задачи, значительно ускоряя общую производительность.
Рассмотрим стандартную схему взаимодействия: клиентское приложение инициирует запуск, сервер создает новый сеанс, выполняет код и сохраняет результат. Наша задача — научиться управлять этим жизненным циклом.
Первым делом выясним причину ограничений: фоновое задание может вызвать только ту процедуру, которая расположена в общем модуле с установленными флажками Сервер и Вызов сервера (или просто Сервер, если вызов идет с серверного кода). Процедура должна быть экспортной.
Разберем пример процедуры, которая будет выполнять длительный расчет и возвращать результат через временное хранилище:
Процедура ВыполнитьРасчетНаСервере(ПараметрыРасчета, АдресХранилища) Экспорт
// Проанализируем входные параметры
ДанныеДляОбработки = ПараметрыРасчета.Данные;
Результат = Новый Структура;
// Эмуляция длительной операции
Для Каждого Строка Из ДанныеДляОбработки Цикл
// Выполняем полезную работу
КонецЦикла;
Результат.Вставить("Статус", "Успешно");
Результат.Вставить("ДатаЗавершения", ТекущаяДата());
// Поместим результат во временное хранилище, чтобы забрать его позже
ПоместитьВоВременноеХранилище(Результат, АдресХранилища);
КонецПроцедуры
Теперь посмотрим на процесс запуска из управляемой формы. Для этого используется менеджер ФоновыеЗадания. Важно помнить, что параметры передаются в виде массива, где порядок элементов должен строго соответствовать порядку аргументов в вызываемой процедуре.
Разберем по шагам алгоритм запуска:
Выполнить менеджера фоновых заданий.
&НаСервере
Функция ЗапуститьЗаданиеНаСервере()
// Создаем уникальный адрес для получения результата
АдресХранилища = ПоместитьВоВременноеХранилище(Неопределено, ЭтаФорма.УникальныйИдентификатор);
ПараметрыПроцедуры = Новый Массив;
ПараметрыПроцедуры.Добавить(ПараметрыДляРобота); // Первый аргумент
ПараметрыПроцедуры.Добавить(АдресХранилища); // Второй аргумент
// Запускаем фоновое задание
НаименованиеЗадания = "Длительный расчет: " + ТекущаяДата();
Задание = ФоновыеЗадания.Выполнить("МойОбщийМодуль.ВыполнитьРасчетНаСервере", ПараметрыПроцедуры, , НаименованиеЗадания);
Возврат Задание.Идентификатор;
КонецФункции
Поскольку задание выполняется асинхронно, нам нужно периодически проверять его состояние. В управляемых формах для этого удобно использовать обработчик ожидания. Выясним, как проверить статус задания по его идентификатору.
Рассмотрим код, который проверяет завершение процесса:
&НаКлиенте
Процедура ПроверитьСтатусЗадания()
Статус = ПолучитьСтатусЗаданияНаСервере(ИдентификаторЗадания);
Если Статус = "Завершено" Тогда
ПодключитьОбработчикОжидания("ПроверитьСтатусЗадания", 0); // Отключаем
ПолучитьРезультат();
ИначеЕсли Статус = "Ошибка" Тогда
ПодключитьОбработчикОжидания("ПроверитьСтатусЗадания", 0);
Сообщить("В ходе выполнения задания произошла ошибка.");
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция ПолучитьСтатусЗаданияНаСервере(ИдЗадания)
Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(ИдЗадания);
Если Задание = Неопределено Тогда
Возврат "Не найдено";
КонецЕсли;
Возврат Строка(Задание.Состояние);
КонецФункции
Проанализируем ситуацию, когда код внутри фонового задания вызывает исключение. В этом случае состояние задания переходит в Ошибка. Чтобы понять, что именно пошло не так, необходимо прочитать свойство ИнформацияОбОшибке объекта ФоновоеЗадание. Важный момент: всегда используйте блоки Попытка...Исключение внутри фоновых процедур и записывайте критические ошибки в ЖурналРегистрации, так как фоновое задание не может вывести сообщение пользователю напрямую через Сообщить.
Посмотрим на пример расширенной обработки завершения:
// В коде проверки на сервере
Если Задание.Состояние = СостояниеФоновогоЗадания.Завершено Аварийно Тогда
ТекстОшибки = Задание.ИнформацияОбОшибке.Описание;
ЗаписьЖурналаРегистрации("ФоновыеЗадания", УровеньЖурналаРегистрации.Ошибка, , , ТекстОшибки);
КонецЕсли;
Рассмотрим подробнее различия сред исполнения. В клиент-серверном варианте (SQL) задания выполняются на сервере приложений 1С сразу после вызова. В файловом же варианте для работы фоновых заданий требуется наличие выделенного сеанса, который будет выполнять роль "планировщика", либо они будут запускаться последовательно при проверке условий в активном сеансе пользователя. Начиная с платформы 8.3.3, в файловом режиме фоновые задания могут запускаться автоматически, если включен параметр ИспользоватьСервисыЗаданий.
Для эффективной работы с фоновыми процессами придерживайтесь следующих правил:
Массив лучше передавать ссылки или простые структуры, а не сами объекты (например, целую таблицу значений). Если данных много, поместите их во ВременноеХранилище и передайте в задание только адрес.Ключ. Если запустить второе задание с тем же ключом, платформа не создаст новый процесс, если старый еще выполняется. Это отличный способ избежать дублирования одинаковых расчетов.Подводя итог, мы проанализировали полный цикл работы с фоновыми задачами. Правильное использование ФоновыеЗадания.Выполнить в сочетании с ВременноеХранилище позволяет создавать производительные и удобные для пользователя решения на базе платформы 1С.