Фоновые и регламентные задания 1С 8.3: запуск из кода, контроль и отладка
Содержание
Фоновое задание в 1С 8.3 запускают серверным методом ФоновыеЗадания.Выполнить("ОбщийМодуль.Процедура", Параметры). Процедура должна быть экспортной и лежать в серверном общем модуле. Из тонкого и веб-клиента напрямую этот метод не вызвать: сначала уходите на сервер (&НаСервере в модуле формы), и уже там стартуете задание.
Частое заблуждение — что фоновое задание «крутится у пользователя» и его можно настроить кнопкой в форме. Нет: оно работает в отдельном сеансе на стороне сервера, без формы и без диалогов. Отсюда и большинство ошибок при запуске. Ниже — код, который работает в тонком, толстом и веб-клиенте, настройка регламентных заданий, получение результата и разбор типовых сбоев.
Как 1С выполняет фоновое задание: сеанс, сервер, контекст
Фоновое задание — это отдельный сеанс информационной базы с типом приложения «Фоновое задание». Он стартует от имени того же пользователя, который запустил задание, и получает его права.
Что важно знать до написания кода:
- 🖥️ Выполняется только серверный код. Метод задания — экспортная процедура общего модуля с флажком «Сервер». Модули форм, модули объектов и клиентские модули не подходят.
- 🚫 Никакого интерфейса.
Вопрос(),ОткрытьФорму(),Предупреждение()в фоне не работают. Сообщения черезСообщить()илиСообщениеПользователюне теряются — они копятся в задании, и их можно забрать. - 📦 Параметры — только сериализуемые. Массив, структура, ссылки, примитивы — да. Форма,
ТабличныйДокументиз формы, объект с несохранёнными изменениями — лучше передавать ссылку или данные в структуре. - 🔁 Параллельность. Вызывающий код не ждёт завершения:
Выполнить()возвращает объектФоновоеЗаданиесразу, а работа идёт параллельно.
Где физически исполняется код, зависит от варианта базы:
| Вариант базы | Кто выполняет фоновое задание | Что учесть |
|---|---|---|
| Клиент-серверный | Рабочий процесс кластера серверов 1С | Нагрузка ложится на сервер, клиенту всё равно, закрыт ли он |
| Файловый, тонкий/толстый клиент | Процесс клиентского приложения, открывшего базу | Закрыли программу — задание прервётся |
| Файловый, веб-клиент | Процесс веб-сервера с публикацией базы | Перезапуск веб-сервера обрывает задание |
В файловой базе фоновое задание живёт ровно столько, сколько живёт процесс, который его запустил. Для длинных обработок на файловой базе держите программу открытой до конца.
Запуск фонового задания из кода: тонкий, толстый и веб-клиент
Базовый вызов
Сначала серверная процедура, которую будет выполнять задание. Создайте общий модуль, например ФоновыеОбработки, и отметьте в его свойствах «Сервер» (флажок «Вызов сервера» здесь не нужен).
// Общий модуль ФоновыеОбработки (Сервер)
Процедура ПересчитатьОстатки(ДатаНачала, АдресРезультата) Экспорт
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ КОЛИЧЕСТВО(*) КАК Всего
|ИЗ Справочник.Номенклатура КАК Н";
Выборка = Запрос.Выполнить().Выбрать();
Выборка.Следующий();
Результат = Новый Структура("Всего, Дата", Выборка.Всего, ТекущаяДатаСеанса());
ПоместитьВоВременноеХранилище(Результат, АдресРезультата);
КонецПроцедуры
Теперь запуск из формы. Клиентская команда уходит на сервер, сервер стартует задание и возвращает его идентификатор:
&НаКлиенте
Перем ИдентификаторЗадания;
&НаКлиенте
Процедура Запустить(Команда)
ИдентификаторЗадания = ЗапуститьНаСервере();
ПодключитьОбработчикОжидания("ПроверитьЗадание", 2, Истина);
КонецПроцедуры
&НаСервере
Функция ЗапуститьНаСервере()
АдресРезультата = ПоместитьВоВременноеХранилище(Неопределено, УникальныйИдентификатор);
Параметры = Новый Массив;
Параметры.Добавить(НачалоМесяца(ТекущаяДатаСеанса()));
Параметры.Добавить(АдресРезультата);
Задание = ФоновыеЗадания.Выполнить(
"ФоновыеОбработки.ПересчитатьОстатки",
Параметры,
"ПересчетОстатков", // ключ: не даст запустить второй экземпляр
"Пересчёт остатков из формы"); // наименование для списка заданий
Возврат Задание.УникальныйИдентификатор;
КонецФункции
АдресРезультата объявите реквизитом формы типа «Строка», чтобы он пережил переход с сервера на клиент.
Четыре параметра ФоновыеЗадания.Выполнить():
- Имя метода — строка
"ИмяМодуля.ИмяПроцедуры". Ошибка в имени выяснится только при запуске. - Параметры — массив; порядок элементов совпадает с порядком параметров процедуры.
- Ключ — необязательный. Пока задание с этим ключом и этим методом активно, второе с тем же ключом не стартует, платформа выдаст исключение.
- Наименование — необязательное, но заполняйте его: так задание проще найти в списке и в журнале регистрации.
Толстый клиент
В обычном приложении (толстый клиент) менеджер ФоновыеЗадания доступен и в клиентском коде. Но пишите так же, как для тонкого клиента
— через серверную процедуру. Тогда код не придётся переделывать при переходе на управляемые формы.
Типовые конфигурации на БСП
В БП 3.0, ЗУП 3.1, УТ 11 и других конфигурациях на Библиотеке стандартных подсистем используют готовый механизм длительных операций. На сервере — ДлительныеОперации.ВыполнитьВФоне() с параметрами из ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор). На клиенте — ДлительныеОперацииКлиент.ОжидатьЗавершение() с описанием оповещения.
Механизм сам показывает индикатор ожидания, передаёт результат и сообщения, обрабатывает аварийное завершение. В доработках типовых конфигураций берите его, а не свой ПодключитьОбработчикОжидания.
Регламентные задания 1С: расписание и ручной запуск
Регламентное задание — это фоновое задание, которое платформа стартует сама по расписанию. Его метод задаётся в метаданных, а не в коде.
Создание в конфигураторе
- В дереве метаданных откройте ветку
Общие → Регламентные заданияи добавьте новый объект. - В поле «Имя метода» выберите экспортную процедуру серверного общего модуля.
- Включите флажок «Предопределенное», если задание должно существовать в базе всегда в одном экземпляре.
- Флажок «Использование» включает задание. Без него расписание игнорируется.
- Задайте расписание: дни, время начала и окончания, период повтора.
- Укажите число повторных попыток при аварийном завершении и интервал между ними — для обменов это спасает от разовых сетевых сбоев.
Для предопределённого задания процедура может быть без параметров. Если в процедуре есть параметры, значения задаются у самого задания в базе.
Включение и расписание в пользовательском режиме
В типовых конфигурациях на БСП список заданий открывается через Администрирование → Обслуживание → Регламентные операции → Регламентные и фоновые задания. Здесь видно последний запуск, его результат и следующее время старта. Двойной щелчок открывает карточку: включить, сменить расписание, указать пользователя, от имени которого задание выполняется.
Для заданий, которые создают или изменяют документы, указывайте пользователя явно. Тогда в журнале регистрации видно, от чьего имени прошли изменения, а права задания совпадают с правами этого пользователя.
Запустить регламентное задание вне расписания
У объекта регламентного задания нет метода «выполнить сейчас». В списке на БСП есть одноимённая команда «Выполнить сейчас» — она стартует фоновое задание с тем же методом и параметрами. Из кода делается то же самое:
&НаСервере
Процедура ВыполнитьОбменСейчас()
МетаданныеЗадания = Метаданные.РегламентныеЗадания.ОбменДанными;
ФоновыеЗадания.Выполнить(МетаданныеЗадания.ИмяМетода, , ,
"Ручной запуск: " + МетаданныеЗадания.Синоним);
КонецПроцедуры
Файловая база: кто запускает регламентные задания
В файловом варианте отдельного сервера нет. Регламентные задания выполняет одно из открытых клиентских приложений — платформа выбирает его сама. Нет открытых сеансов — задания не выполняются.
Управлять этим можно параметром командной строки /AllowExecuteScheduledJobs:
-Off— этот экземпляр клиента никогда не выполняет регламентные задания;-Force— выполняет их принудительно.
На файловой базе с обменами по расписанию часто держат отдельный ярлык с -Force на машине, которая включена круглосуточно.
Результат фонового задания и оповещение пользователя
Задание работает отдельно от формы, поэтому результат забирают тремя способами.
| Что нужно получить | Чем | Где |
|---|---|---|
| Данные (таблица, структура, файл) | ПоместитьВоВременноеХранилище() в задании → ПолучитьИзВременногоХранилища() в форме | Сервер |
| Тексты сообщений | Задание.ПолучитьСообщенияПользователю(Истина) | Сервер |
| Состояние и текст ошибки | Задание.Состояние, Задание.ИнформацияОбОшибке | Сервер |
Проверка состояния по обработчику ожидания:
&НаКлиенте
Процедура ПроверитьЗадание()
Состояние = СостояниеЗаданияНаСервере(ИдентификаторЗадания);
Если Состояние = "Активно" Тогда
ПодключитьОбработчикОжидания("ПроверитьЗадание", 2, Истина);
ИначеЕсли Состояние = "Завершено" Тогда
ПоказатьОповещениеПользователя("Пересчёт завершён");
ЗагрузитьРезультат();
Иначе
ПоказатьПредупреждение(, "Задание не выполнено: " + Состояние);
КонецЕсли;
КонецПроцедуры
&НаСервереБезКонтекста
Функция СостояниеЗаданияНаСервере(Идентификатор)
Задание = ФоновыеЗадания.НайтиПоУникальномуИдентификатору(Идентификатор);
Если Задание = Неопределено Тогда
Возврат "Не найдено";
КонецЕсли;
Если Задание.Состояние = СостояниеФоновогоЗадания.Активно Тогда
Возврат "Активно";
ИначеЕсли Задание.Состояние = СостояниеФоновогоЗадания.Завершено Тогда
Возврат "Завершено";
ИначеЕсли Задание.Состояние = СостояниеФоновогоЗадания.ЗавершеноАварийно Тогда
Возврат ПодробноеПредставлениеОшибки(Задание.ИнформацияОбОшибке);
КонецЕсли;
Возврат "Отменено";
КонецФункции
ЗагрузитьРезультат() — ваша серверная процедура, которая читает ПолучитьИзВременногоХранилища(АдресРезультата) и выводит данные на форму.
Несколько практических правил:
- ⏱️ Интервал проверки — 1–5 секунд. Опрос каждые 0,1 секунды создаёт лишние серверные вызовы, особенно когда форму открыли 50 пользователей.
- 🧹 Хранилище привязывайте к форме. Адрес, полученный с
УникальныйИдентификаторформы, очищается при её закрытии. Без этого данные висят до конца сеанса. - ✋ Дайте кнопку отмены.
Задание.Отменить()на сервере ставит задание в состояние «Отменено». Код в задании не прерывается посреди записи — отмена срабатывает между операциями, поэтому длинный цикл не остановится мгновенно. - 📣 Оповещайте после закрытия формы. Если пользователь закрыл форму, обработчик ожидания исчезнет вместе с ней. Для долгих заданий пишите итог в журнал регистрации или в регистр, а пользователю показывайте его при следующем открытии.
Отладка фонового задания
Точка останова в процедуре фонового задания по умолчанию не срабатывает: отладчик подключён к клиентскому сеансу, а задание — другой сеанс.
Порядок для конфигуратора:
- Запустите отладку как обычно (F5).
- В Конфигураторе откройте
Отладка → Подключениеи включите автоматическое подключение для фоновых заданий. - Поставьте точку останова в процедуре общего модуля и запустите задание.
Для клиент-серверной базы сервер 1С должен работать в режиме отладки (служба запускается с ключом -debug). На рабочем сервере этот режим не держат постоянно: он замедляет работу.
Быстрый путь без отладчика: временно вызовите процедуру задания напрямую в серверной процедуре формы вместо ФоновыеЗадания.Выполнить(). Ошибка всплывёт сразу, с номером строки. В БСП для этого есть параметр выполнения, который запускает длительную операцию в текущем сеансе, а не в фоне.
Почему фоновое или регламентное задание не запускается
Большинство сбоев видно в журнале регистрации: Администрирование → Обслуживание → Журнал регистрации, отбор по приложению «Фоновое задание» и по уровню «Ошибка».
Если в консоли администрирования решите принудительно завершить зависший сеанс фонового задания, учтите: незавершённая транзакция откатится, а все данные, которые задание успело записать вне транзакции, останутся. Делайте это, когда задание точно не пишет в базу важную порцию, и предупредите пользователей, если задание запускал кто-то из них.
Нагрузка на сервер: как не перегрузить базу фоновыми заданиями
Фоновые задания удобны тем, что их легко запускать. Именно поэтому они чаще всего и перегружают сервер.
Расписание
- 📅 Разносите тяжёлые задания по времени. Обмен, пересчёт итогов, полнотекстовый индекс и загрузка банковских выписок в одну и ту же минуту дают пик блокировок.
- ⏳ Не ставьте период повтора меньше времени выполнения. Если обмен идёт 4 минуты, повтор каждые 60 секунд не ускорит его: следующий запуск просто не стартует, пока активен предыдущий, или упрётся в блокировки.
- 🌙 Тяжёлое — ночью. Обновление индекса полнотекстового поиска и пересчёт агрегатов в рабочие часы замедляют проведение документов.
Код задания
- 🧩 Порции вместо одной транзакции. Обработка 100 000 документов одной транзакцией держит блокировки весь час работы. Порции по 500–1000 объектов со своей транзакцией каждая освобождают таблицы между порциями.
- 🔀 Параллельные потоки — осторожно. Разбить данные на 4 части и запустить 4 фоновых задания реально ускоряет обработку на сервере с несколькими ядрами. Но части не должны пересекаться по данным, иначе потоки будут ждать друг друга на управляемых блокировках. В свежих версиях БСП для этого есть готовые функции многопоточного выполнения в модуле
ДлительныеОперации. - 📉 Не ждите задание синхронно.
ОжидатьЗавершенияВыполнения()на сервере блокирует серверный вызов формы. Если ждать всё равно приходится, задавайте таймаут в секундах.
Контроль
В консоли администрирования серверов в списке сеансов фоновые задания видны с типом приложения «Фоновое задание». Длинный список таких сеансов при обычной нагрузке — признак, что задания не успевают завершиться до следующего запуска.
Код для быстрой проверки, что сейчас выполняется в базе:
&НаСервереБезКонтекста
Функция АктивныеЗадания()
Отбор = Новый Структура("Состояние", СостояниеФоновогоЗадания.Активно);
Результат = Новый Массив;
Для Каждого Задание Из ФоновыеЗадания.ПолучитьФоновыеЗадания(Отбор) Цикл
Результат.Добавить(Задание.Наименование + " — с " + Формат(Задание.Начало, "ДФ=HH:mm:ss"));
КонецЦикла;
Возврат Результат;
КонецФункции
Частые вопросы
Можно ли запустить фоновое задание из модуля объекта или обработки?
ФоновыеЗадания.Выполнить() с именем процедуры общего модуля, а нужный объект передайте ссылкой в параметрах.Как запустить внешнюю обработку в фоне?
Сколько фоновых заданий можно запускать одновременно?
Нужна ли отдельная лицензия для фонового задания?
Можно ли запустить фоновое задание из другого фонового задания?
ФоновыеЗадания.Выполнить() работает. Так устроены многопоточные обработки: управляющее задание делит данные на порции и стартует несколько дочерних, а затем собирает их результаты.