ФоновыеЗадания.Выполнить: запуск кода в фоне, параметры, контроль и отладка
Содержание
Программно фоновое задание в 1С 8.3 запускают на сервере методом ФоновыеЗадания.Выполнить("ОбщийМодуль.Процедура", МассивПараметров, Ключ, Наименование). Процедура должна быть экспортной и лежать в серверном общем модуле. Метод сразу возвращает объект ФоновоеЗадание, а код продолжает работу, не дожидаясь окончания.
Есть два пути. Голый вызов платформы подходит для простых задач: пересчитать регистр, выгрузить файл, отправить письма. В конфигурациях на БСП (Бухгалтерия 3.0, ЗУП 3.1, УТ 11) удобнее обёртка ДлительныеОперации.ВыполнитьВФоне: она сама передаёт результат в форму, показывает индикатор и корректно работает в файловой базе. Ниже оба варианта, с кодом, правами и разбором ошибок.
Как устроены фоновые задания в платформе 1С
Фоновое задание — это отдельный сеанс информационной базы без интерфейса. Он стартует по команде из кода, выполняет одну процедуру и завершается.
Чем фоновое задание отличается от обычного серверного вызова:
- ⏱ Не блокирует пользователя. Форма остаётся доступной, можно показывать прогресс.
- 🔀 Работает параллельно. Несколько заданий идут одновременно в разных сеансах — так ускоряют длинные обработки, разбив данные на порции.
- 🚫 Нет интерфейса. Формы,
Вопрос(),Предупреждение()и любые клиентские методы недоступны. - 👤 Работает от имени пользователя, который его запустил, с его ролями.
Фоновые задания путают с регламентными. Разница простая:
| Что | Кто запускает | Где описано | Когда использовать |
|---|---|---|---|
| Фоновое задание | Ваш код, в любой момент | Нигде, только вызов метода | Разовые долгие операции по команде |
| Регламентное задание | Платформа по расписанию | Объект метаданных «Регламентное задание» | Периодические операции: обмен, закрытие, загрузка курсов |
Регламентное задание при каждом срабатывании тоже выполняется как фоновое. Поэтому в списке фоновых заданий вы увидите и свои, и порождённые расписанием.
Клиент-серверный и файловый вариант
В клиент-серверной базе задание выполняет рабочий процесс сервера 1С. Пользователь может закрыть программу — задание доработает.
В файловой базе отдельного сервера нет. Задания выполняет процесс приложения, которое открыло базу: тонкий или толстый клиент либо модуль веб-сервера при публикации. Закрыли программу — незавершённое задание оборвалось. Для долгих операций в файловой базе это нужно учитывать и предупреждать пользователя.
Синтаксис ФоновыеЗадания.Выполнить и его параметры
Метод доступен на сервере, в толстом клиенте и во внешнем соединении. Из модуля формы его вызывают через серверную процедуру с директивой &НаСервере.
ФоновыеЗадания.Выполнить(<ИмяМетода>, <Параметры>, <Ключ>, <Наименование>)
| Параметр | Тип | Обязательный | Что передавать |
|---|---|---|---|
| ИмяМетода | Строка | Да | "ИмяМодуля.ИмяПроцедуры" — экспортная процедура серверного общего модуля |
| Параметры | Массив | Нет | Значения параметров процедуры по порядку |
| Ключ | Строка | Нет | Защита от повторного запуска одного и того же |
| Наименование | Строка | Нет | Понятное имя для списка заданий и журнала |
Минимальный рабочий пример. Общий модуль ФоновыеОбработки с флажком «Сервер», флажок «Глобальный» снят:
// Общий модуль ФоновыеОбработки
Процедура ПересчитатьОстатки(ДатаНачала, ДатаОкончания) Экспорт
ЗаписьЖурналаРегистрации("Пересчёт остатков",
УровеньЖурналаРегистрации.Информация, , ,
СтрШаблон("Период %1 – %2", Формат(ДатаНачала, "ДФ=dd.MM.yyyy"),
Формат(ДатаОкончания, "ДФ=dd.MM.yyyy")));
// ... основная работа
КонецПроцедуры
Запуск из формы:
&НаСервере
Процедура ЗапуститьПересчётНаСервере()
Параметры = Новый Массив;
Параметры.Добавить(Объект.ДатаНачала);
Параметры.Добавить(Объект.ДатаОкончания);
Задание = ФоновыеЗадания.Выполнить(
"ФоновыеОбработки.ПересчитатьОстатки",
Параметры,
"ПересчётОстатков",
"Пересчёт остатков за период");
ИдентификаторЗадания = Задание.УникальныйИдентификатор;
КонецПроцедуры
ИдентификаторЗадания — реквизит формы типа УникальныйИдентификатор. По нему потом проверяют состояние задания.
Ключ работает так: пока активно задание с тем же методом и тем же ключом, второй запуск вызывает исключение. Это готовая защита от двойного нажатия кнопки. Чтобы ограничить одно задание на документ, добавьте в ключ его уникальный идентификатор: "Проведение_" + Строка(Ссылка.УникальныйИдентификатор()).
Процедура задания: передача параметров и возврат результата
Количество элементов массива Параметры должно совпадать с числом параметров процедуры. Порядок тот же, что в объявлении.
Что можно передавать
Задание стартует в другом сеансе, поэтому значения передаются копией. Безопасно передавать:
- ✅ примитивные типы: строки, числа, даты, булево;
- ✅ ссылки на объекты базы;
- ✅ структуры и массивы из таких значений;
- ✅ адрес во временном хранилище — строкой.
Не передавайте:
- ❌ данные формы и сами формы;
- ❌ менеджер временных таблиц;
- ❌ объекты, которые нельзя сериализовать (запрос с открытым результатом, COM-объекты).
Большую таблицу значений проще положить во временное хранилище и передать в задание только адрес.
Как вернуть результат
Процедура фонового задания ничего не возвращает в вызывающий код. Результат кладут во временное хранилище. Адрес заранее создают на стороне формы и передают параметром:
&НаСервере
Процедура ЗапуститьОтчётНаСервере()
АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено, УникальныйИдентификатор);
Параметры = Новый Массив;
Параметры.Добавить(Объект.Организация);
Параметры.Добавить(АдресРезультата);
Задание = ФоновыеЗадания.Выполнить("ФоновыеОбработки.СобратьДанные", Параметры, , "Сбор данных");
ИдентификаторЗадания = Задание.УникальныйИдентификатор;
КонецПроцедуры
// Общий модуль ФоновыеОбработки
Процедура СобратьДанные(Организация, АдресРезультата) Экспорт
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Контрагенты.Ссылка КАК Контрагент
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| НЕ Контрагенты.ПометкаУдаления";
Таблица = Запрос.Выполнить().Выгрузить();
ПоместитьВоВременноеХранилище(Таблица, АдресРезультата);
КонецПроцедуры
После завершения задания форма забирает таблицу через ПолучитьИзВременногоХранилища(АдресРезультата). Хранилище привязано к уникальному идентификатору формы и живёт, пока форма открыта.
Обёртка БСП: ДлительныеОперации
В типовых конфигурациях тот же сценарий короче. Процедура пишется с двумя параметрами — Параметры и АдресРезультата, — а запуск и ожидание берёт на себя библиотека:
&НаСервере
Функция ЗапуститьНаСервере()
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
ПараметрыВыполнения.НаименованиеФоновогоЗадания = "Сбор данных";
ПараметрыПроцедуры = Новый Структура("Организация", Объект.Организация);
Возврат ДлительныеОперации.ВыполнитьВФоне("ФоновыеОбработки.СобратьДанныеБСП",
ПараметрыПроцедуры, ПараметрыВыполнения);
КонецФункции
&НаКлиенте
Процедура Сформировать(Команда)
ДлительнаяОперация = ЗапуститьНаСервере();
ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
Оповещение = Новый ОписаниеОповещения("ПослеЗавершения", ЭтотОбъект);
ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, Оповещение, ПараметрыОжидания);
КонецПроцедуры
&НаКлиенте
Процедура ПослеЗавершения(Результат, ДополнительныеПараметры) Экспорт
Если Результат = Неопределено Тогда
Возврат; // пользователь отменил
КонецЕсли;
Если Результат.Статус = "Выполнено" Тогда
ЗагрузитьРезультат(Результат.АдресРезультата);
ИначеЕсли Результат.Статус = "Ошибка" Тогда
ПоказатьПредупреждение(, Результат.КраткоеПредставлениеОшибки);
КонецЕсли;
КонецПроцедуры
Состав полей структуры Результат зависит от версии БСП. Сверьте его с описанием функции ОжидатьЗавершение в общем модуле ДлительныеОперацииКлиент вашей конфигурации — комментарий над функцией перечисляет все поля.
Свои общие модули не добавляйте прямо в типовую конфигурацию. Положите их в расширение: при обновлении релиза доработка не потеряется, а обёртка БСП из расширения вызывается так же.
Права и роли для фоновой обработки
Отдельного права «запускать фоновые задания» в платформе нет. Задание получает права пользователя, который его запустил:
- 🔑 Если у пользователя нет права чтения регистра, процедура задания упадёт на первом же запросе к нему.
- 🔑 Ограничения доступа на уровне записей (RLS) действуют и в фоне.
- 🔑 Параметры сеанса в фоновом сеансе устанавливаются заново, через модуль сеанса.
Когда процедура должна сделать больше, чем разрешено пользователю, есть два приёма.
- Привилегированный режим в коде. В начале процедуры
УстановитьПривилегированныйРежим(Истина), в конце —Ложь. Режим действует только на сервере. - Привилегированный общий модуль. В свойствах модуля флажок «Привилегированный». Весь код модуля выполняется без проверки прав.
Привилегированный режим отключает все проверки прав и RLS. Не передавайте в такую процедуру произвольные строки запроса или имена объектов от пользователя: это готовая дыра в доступе.
Регламентные задания, запущенные по расписанию, работают от пользователя, указанного в их свойствах. Если пользователь не указан, задание выполняется без ограничения прав. Это одна из частых причин расхождения: из формы обработка падает с ошибкой прав, а по расписанию проходит.
Мониторинг состояния и управление заданиями
Проверка из кода
Найти задание по идентификатору и узнать его состояние:
&НаСервереБезКонтекста
Функция СостояниеЗадания(Идентификатор)
Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(Идентификатор);
Если Задание = Неопределено Тогда
Возврат "НеНайдено";
КонецЕсли;
Если Задание.Состояние = СостояниеФоновогоЗадания.Активно Тогда
Возврат "Активно";
ИначеЕсли Задание.Состояние = СостояниеФоновогоЗадания.Завершено Тогда
Возврат "Завершено";
ИначеЕсли Задание.Состояние = СостояниеФоновогоЗадания.ЗавершеноАварийно Тогда
Возврат ПодробноеПредставлениеОшибки(Задание.ИнформацияОбОшибке);
Иначе
Возврат "Отменено";
КонецЕсли;
КонецФункции
На клиенте эту функцию опрашивают через ПодключитьОбработчикОжидания("ПроверитьЗадание", 2, Ложь) и отключают обработчик, когда задание перестало быть активным. Опрос раз в 1–2 секунды достаточен: частые серверные вызовы сами создают нагрузку.
Полезные свойства и методы объекта ФоновоеЗадание:
| Свойство или метод | Что даёт |
|---|---|
Состояние | Активно, Завершено, ЗавершеноАварийно, Отменено |
Начало, Конец | Время старта и окончания |
ИнформацияОбОшибке | Описание исключения при аварийном завершении |
ПолучитьСообщенияПользователю(Истина) | Сообщения, выведенные в задании через Сообщение.Сообщить() |
Отменить() | Остановить задание |
ОжидатьЗавершенияВыполнения(Таймаут) | Ждать окончания на сервере, в секундах |
Список заданий с отбором — ФоновыеЗадания.ПолучитьФоновыеЗадания(Новый Структура("Ключ, Состояние", "ПересчётОстатков", СостояниеФоновогоЗадания.Активно)). Внутри самого задания ссылку на себя даёт ПолучитьТекущийСеансИнформационнойБазы().ПолучитьФоновоеЗадание().
Параллельный запуск порциями
Длинную обработку можно разбить: например, 5 заданий по 2 000 документов вместо одного на 10 000. Запустите задания в цикле, сложите объекты в массив и дождитесь всех сразу:
Задания = Новый Массив;
Для Каждого Порция Из Порции Цикл
Параметры = Новый Массив;
Параметры.Добавить(Порция);
Задания.Добавить(ФоновыеЗадания.Выполнить("ФоновыеОбработки.ОбработатьПорцию", Параметры));
КонецЦикла;
ФоновыеЗадания.ОжидатьЗавершенияВыполнения(Задания);
Число параллельных заданий подбирайте под сервер. Больше потоков, чем ядер у рабочих процессов, выигрыша не даст, а риск блокировок на одних и тех же таблицах вырастет.
Где посмотреть задания без кода
- 🖥 В типовой конфигурации:
Администрирование → Обслуживание → Регламентные операции → Регламентные и фоновые задания, вкладка с фоновыми заданиями. Там видны состояние, время, текст ошибки, и задание можно отменить. - 🖥 В консоли администрирования кластера: фоновые задания показаны в списке сеансов базы как отдельные сеансы. Отсюда сеанс можно завершить.
- 📒 В журнале регистрации: события группы «Фоновое задание» — запуск, успешное завершение, ошибка, отмена.
Завершение сеанса фонового задания в консоли кластера обрывает его на полуслове. Если задание писало данные порциями без общей транзакции, часть изменений останется. Сначала пробуйте мягкую отмену Отменить(), а консоль оставьте на случай зависания.
Отладка фоновых заданий и типичные ошибки
Как поймать точку останова
Обычная точка останова в процедуре задания не срабатывает: код идёт в другом сеансе. Порядок действий:
- В Конфигураторе откройте
Отладка → Подключение. - Нажмите кнопку автоматического подключения и отметьте тип «Фоновое задание».
- Поставьте точку останова в процедуре общего модуля и запустите задание.
Для клиент-серверной базы сервер 1С должен быть запущен с отладкой — без этого отладчик к серверным сеансам не подключится.
Приём попроще на время разработки: вызовите ту же процедуру напрямую в серверной процедуре формы, без ФоновыеЗадания.Выполнить. Логика отлаживается как обычный серверный код, а в фон переводится одной строкой.
Разбор ошибок
Ещё две ошибки, которые не дают исключения, но портят данные:
- 🔁 Задание запускают в цикле без ключа. Пользователь дважды нажал кнопку — два задания параллельно пишут одни и те же документы. Ключ решает это одной строкой.
- 🧹 Нет записи в журнал. Если задание упало ночью, через неделю причину уже не восстановить. Пишите
ЗаписьЖурналаРегистрациив начале, в конце и в обработке исключения.