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