Длительные операции 1С БСП: ВыполнитьФункцию с прогрессом

Дата: 06.10.2026 16:54:16
БСП
Длительные операции
Фоновые задания
Управляемые формы
Временное хранилище
Комментарий:
0
Платформа:
8.3
Конфигурация:
Любая
Формы:
Управляемые

Длительные операции 1С — подсистема БСП, которая переносит тяжёлый серверный вызов в фоновое задание, показывает пользователю окно ожидания или индикатор на форме и возвращает результат через временное хранилище. Вместо ручного ФоновыеЗадания.Выполнить с обработчиком ожидания хватает двух вызовов: ДлительныеОперации.ВыполнитьФункцию на сервере и ДлительныеОперацииКлиент.ОжидатьЗавершение на клиенте. Ниже — полный код обработки с прогрессом, отменой и чтением результата для платформы 8.3. Имена методов и параметров сверены по БСП из УТ 11.4 и КА 2.5.

Где встречаются длительные операции

Пользователь видит этот механизм постоянно: окно «Пожалуйста, подождите...» с кнопкой «Отмена», надпись «Отчет формируется...» в отчётах (так в УТ 11.4), индикатор при загрузке данных из файла. В УТ 11.4 на длительных операциях построены общая форма ФормаОтчета и обработки ЗагрузкаДанныхИзФайла, ПоискИУдалениеДублей, УдалениеПомеченныхОбъектов — их модули форм стоит открыть как образец.

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

Как устроены длительные операции 1С в БСП

Схема выполнения длительной операции — из трёх частей. Экспортная функция, которая делает работу, лежит в общем модуле или модуле менеджера. Серверная процедура формы запускает её через ВыполнитьФункцию и получает структуру с состоянием. Клиент передаёт структуру в ОжидатьЗавершение вместе с ОписаниеОповещения: БСП сама проверяет задание и вызывает обработчик по окончании. Код подсистемы — в конфигураторе: «Общие» → «Общие модули» → ДлительныеОперации и ДлительныеОперацииКлиент, окно ожидания — общая форма ДлительнаяОперация.

МетодГде вызыватьЧто делает
ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполнения, ИмяФункции, Параметр1, …, Параметр7)СерверЗапускает экспортную функцию в фоне, её результат БСП кладёт во временное хранилище
ДлительныеОперации.ВыполнитьПроцедуру(ПараметрыВыполнения, ИмяПроцедуры, Параметр1, …, Параметр7)СерверТо же для процедуры, результата нет
ПараметрыВыполненияФункции(ИдентификаторФормы), ПараметрыВыполненияПроцедуры()СерверНастройки запуска: НаименованиеФоновогоЗадания, КлючФоновогоЗадания, ОжидатьЗавершение, ЗапуститьВФоне, ЗапуститьНеВФоне
ДлительныеОперации.СообщитьПрогресс(Процент, Текст, ДополнительныеПараметры)Код в фонеПередаёт на клиент процент и текст
ДлительныеОперации.ОтменитьВыполнениеЗадания(ИдентификаторЗадания)СерверОтменяет задание
ДлительныеОперацииКлиент.ПараметрыОжидания(ФормаВладелец)КлиентОкно ожидания, прогресс, сообщения, интервал проверки
ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация, ОповещениеОЗавершении, ПараметрыОжидания)КлиентЖдёт завершения и вызывает обработчик оповещения

ВыполнитьФункцию возвращает структуру: Статус («Выполняется», «Выполнено», «Ошибка» или «Отменено»), ИдентификаторЗадания, АдресРезультата, КраткоеПредставлениеОшибки, ПодробноеПредставлениеОшибки, Сообщения. Обработчик оповещения получает похожую структуру или Неопределено, если задание отменили. В БСП из КА 2.5 в результате есть ещё ИнформацияОбОшибке, а для многопоточной обработки появились ВыполнитьФункциюВНесколькоПотоков и ВыполнитьПроцедуруВНесколькоПотоков. ОписаниеОповещения не путайте с Оповестить() между формами — о нём отдельная статья.

Пример: поиск неиспользуемой номенклатуры в фоне

Задача: найти позиции номенклатуры, на которые нигде нет ссылок, например после неудачной загрузки, и пометить их на удаление. НайтиПоСсылкам просматривает все таблицы базы, и на большой базе такой поиск идёт долго — типичная длительная операция. Создайте обработку ПоискНеиспользуемойНоменклатуры в конфигурации или в расширении: для внешней обработки механизм работает иначе, см. «Типичные ошибки». Справочник Номенклатура и исключаемые таблицы сверены по УТ 11.4 и КА 2.5.

Модуль менеджера: код, который выполняется в фоне

// Модуль менеджера обработки «ПоискНеиспользуемойНоменклатуры».
// Обработка — в конфигурации или в расширении, не внешняя.
// Методы запускает форма через ДлительныеОперации, выполняются они в фоне.

#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда

#Область ПрограммныйИнтерфейс

// Возвращает номенклатуру, на которую нет ссылок в базе.
//
// Параметры:
//  Группа - СправочникСсылка.Номенклатура - где искать; пустая ссылка - весь справочник.
//  ИсключаемыеТаблицы - Массив из Строка - полные имена таблиц, ссылки из которых
//                       не считаются использованием, например "РегистрСведений.ВерсииОбъектов".
//
// Возвращаемое значение:
//  ТаблицаЗначений - колонки Номенклатура и Наименование.
//
Функция НеиспользуемаяНоменклатура(Знач Группа, Знач ИсключаемыеТаблицы) Экспорт

	Кандидаты = НоменклатураДляПроверки(Группа);
	Результат = Кандидаты.СкопироватьКолонки();
	Всего = Кандидаты.Количество();
	Проверено = 0;
	ПоследнийПроцент = -1;
	Порция = Новый Массив;

	// Поиск ссылок идёт по всем таблицам базы, и его результат не должен зависеть
	// от прав пользователя: так же делает БСП в ОбщегоНазначения.ЕстьСсылкиНаОбъект.
	УстановитьПривилегированныйРежим(Истина);

	Для Каждого Кандидат Из Кандидаты Цикл

		Порция.Добавить(Кандидат);
		Проверено = Проверено + 1;
		Если Порция.Количество() < 200 И Проверено < Всего Тогда
			Продолжить;
		КонецЕсли;

		ДобавитьНеиспользуемые(Порция, ИсключаемыеТаблицы, Результат);
		Порция.Очистить();

		// БСП советует сообщать прогресс не больше 100 раз за операцию,
		// поэтому отправляем его, только когда сменился целый процент.
		Процент = Цел(Проверено * 100 / Всего);
		Если Процент <> ПоследнийПроцент Тогда
			ПоследнийПроцент = Процент;
			ДлительныеОперации.СообщитьПрогресс(Процент, СтрШаблон(
				НСтр("ru = 'Проверено %1 из %2, без ссылок: %3'"), Проверено, Всего, Результат.Количество()));
		КонецЕсли;

	КонецЦикла;

	УстановитьПривилегированныйРежим(Ложь);

	Возврат Результат;

КонецФункции

// Тот же поиск в формате ДлительныеОперации.ВыполнитьВФоне:
// параметры приходят одной структурой, результат процедура кладёт сама.
//
Процедура НеиспользуемаяНоменклатураВФоне(Параметры, АдресРезультата) Экспорт

	Результат = НеиспользуемаяНоменклатура(Параметры.Группа, Параметры.ИсключаемыеТаблицы);
	ПоместитьВоВременноеХранилище(Результат, АдресРезультата);

КонецПроцедуры

// Помечает номенклатуру на удаление. Каждая позиция записывается отдельно,
// поэтому отмена задания или ошибка на одной позиции не откатывают уже помеченные.
//
// Параметры:
//  Список - Массив из СправочникСсылка.Номенклатура
//
Процедура ПометитьНаУдаление(Знач Список) Экспорт

	Всего = Список.Количество();
	ПоследнийПроцент = -1;

	Для Номер = 1 По Всего Цикл

		Ссылка = Список[Номер - 1];
		Попытка
			НоменклатураОбъект = Ссылка.ПолучитьОбъект();
			НоменклатураОбъект.УстановитьПометкуУдаления(Истина);
		Исключение
			// Попадёт в сообщения формы, если в ПараметрыОжидания ВыводитьСообщения = Истина.
			ОбщегоНазначения.СообщитьПользователю(СтрШаблон(НСтр("ru = 'Не помечена «%1»: %2'"),
				Ссылка, КраткоеПредставлениеОшибки(ИнформацияОбОшибке())));
		КонецПопытки;

		Процент = Цел(Номер * 100 / Всего);
		Если Процент <> ПоследнийПроцент Тогда
			ПоследнийПроцент = Процент;
			ДлительныеОперации.СообщитьПрогресс(Процент,
				СтрШаблон(НСтр("ru = 'Обработано %1 из %2'"), Номер, Всего));
		КонецЕсли;

	КонецЦикла;

КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция НоменклатураДляПроверки(Группа)

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Номенклатура.Ссылка КАК Номенклатура,
	|	Номенклатура.Наименование КАК Наименование
	|ИЗ
	|	Справочник.Номенклатура КАК Номенклатура
	|ГДЕ
	|	НЕ Номенклатура.ЭтоГруппа
	|	И НЕ Номенклатура.ПометкаУдаления
	|	И (&ВесьСправочник
	|			ИЛИ Номенклатура.Ссылка В ИЕРАРХИИ (&Группа))
	|
	|УПОРЯДОЧИТЬ ПО
	|	Наименование";
	Запрос.УстановитьПараметр("Группа", Группа);
	Запрос.УстановитьПараметр("ВесьСправочник", Не ЗначениеЗаполнено(Группа));

	Возврат Запрос.Выполнить().Выгрузить();

КонецФункции

Процедура ДобавитьНеиспользуемые(СтрокиПорции, ИсключаемыеТаблицы, Результат)

	Ссылки = Новый Массив;
	Для Каждого СтрокаПорции Из СтрокиПорции Цикл
		Ссылки.Добавить(СтрокаПорции.Номенклатура);
	КонецЦикла;

	// Один проход по таблицам базы на всю порцию, а не на каждую позицию.
	// Ходовой товар даёт тысячи строк результата, поэтому порции небольшие.
	Используемые = Новый Соответствие;
	Для Каждого МестоИспользования Из НайтиПоСсылкам(Ссылки) Цикл
		Если ИсключаемыеТаблицы.Найти(МестоИспользования.Метаданные.ПолноеИмя()) = Неопределено Тогда
			Используемые.Вставить(МестоИспользования.Ссылка, Истина);
		КонецЕсли;
	КонецЦикла;

	Для Каждого СтрокаПорции Из СтрокиПорции Цикл
		Если Используемые[СтрокаПорции.Номенклатура] = Неопределено Тогда
			ЗаполнитьЗначенияСвойств(Результат.Добавить(), СтрокаПорции);
		КонецЕсли;
	КонецЦикла;

КонецПроцедуры

#КонецОбласти

#КонецЕсли

Модуль формы: запуск, прогресс, отмена и результат

На форме — поле группы, таблица Неиспользуемые с флажком и группа ГруппаПрогресс с полем индикатора и кнопкой «Прервать». Реквизиты и элементы создаются как в любой управляемой форме. Поиск показывает прогресс прямо на форме, пометка — в стандартном окне ожидания, так что в одном модуле есть оба варианта.

// Модуль формы обработки «ПоискНеиспользуемойНоменклатуры».
// Реквизиты формы:
//   Группа - СправочникСсылка.Номенклатура;
//   Неиспользуемые - ТаблицаЗначений с колонками Пометка (Булево),
//     Номенклатура (СправочникСсылка.Номенклатура), Наименование (Строка);
//   ПроцентВыполнения - Число, к нему привязано поле индикатора с максимумом 100;
//   ТекстСостояния - Строка.
// Группа ГруппаПрогресс: поле индикатора, поле ТекстСостояния и кнопка команды ПрерватьПоиск.
// Команды: НайтиНеиспользуемые, ПрерватьПоиск, ПометитьВыбранные.

#Область ОписаниеПеременных

&НаКлиенте
Перем ИдентификаторЗадания; // задание поиска, пока оно выполняется

#КонецОбласти

#Область ОбработчикиСобытийФормы

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

	Элементы.ГруппаПрогресс.Видимость = Ложь;

КонецПроцедуры

#КонецОбласти

#Область ОбработчикиКомандФормы

&НаКлиенте
Процедура НайтиНеиспользуемые(Команда)

	Если ИдентификаторЗадания <> Неопределено Тогда
		ПоказатьПредупреждение(, НСтр("ru = 'Поиск уже выполняется.'"));
		Возврат;
	КонецЕсли;

	ДлительнаяОперация = НачатьПоискНаСервере();
	ИдентификаторЗадания = ДлительнаяОперация.ИдентификаторЗадания;
	ПроцентВыполнения = 0;
	ТекстСостояния = НСтр("ru = 'Поиск запущен'");
	Элементы.ГруппаПрогресс.Видимость = (ДлительнаяОперация.Статус = "Выполняется");

	// Своя индикация на форме вместо окна ожидания: форма не блокируется.
	ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
	ПараметрыОжидания.ВыводитьОкноОжидания = Ложь;
	ПараметрыОжидания.ВыводитьПрогрессВыполнения = Истина;
	ПараметрыОжидания.ОповещениеОПрогрессеВыполнения = Новый ОписаниеОповещения("ПоискПрогресс", ЭтотОбъект);
	ПараметрыОжидания.Интервал = 2; // проверка раз в 2 с вместо интервала, растущего до 15 с

	ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация,
		Новый ОписаниеОповещения("ПоискЗавершение", ЭтотОбъект), ПараметрыОжидания);

КонецПроцедуры

&НаКлиенте
Процедура ПрерватьПоиск(Команда)

	Если ИдентификаторЗадания = Неопределено Тогда
		Возврат;
	КонецЕсли;

	// При следующей проверке БСП увидит отмену и вызовет ПоискЗавершение с Неопределено.
	ОтменитьЗаданиеНаСервере(ИдентификаторЗадания);
	ТекстСостояния = НСтр("ru = 'Поиск прерывается...'");

КонецПроцедуры

&НаКлиенте
Процедура ПометитьВыбранные(Команда)

	ДлительнаяОперация = НачатьПометкуНаСервере();
	Если ДлительнаяОперация = Неопределено Тогда
		ПоказатьПредупреждение(, НСтр("ru = 'Отметьте флажками позиции, которые нужно пометить на удаление.'"));
		Возврат;
	КонецЕсли;

	// Стандартное окно «Пожалуйста, подождите...» с процентом и кнопкой «Отмена».
	ПараметрыОжидания = ДлительныеОперацииКлиент.ПараметрыОжидания(ЭтотОбъект);
	ПараметрыОжидания.ТекстСообщения = НСтр("ru = 'Пометка номенклатуры на удаление'");
	ПараметрыОжидания.ВыводитьПрогрессВыполнения = Истина;
	ПараметрыОжидания.ВыводитьСообщения = Истина; // ошибки по позициям — в сообщения этой формы
	ПараметрыОжидания.ОповещениеПользователя.Показать = Истина;
	ПараметрыОжидания.ОповещениеПользователя.Текст = НСтр("ru = 'Пометка на удаление завершена'");

	ДлительныеОперацииКлиент.ОжидатьЗавершение(ДлительнаяОперация,
		Новый ОписаниеОповещения("ПометкаЗавершение", ЭтотОбъект), ПараметрыОжидания);

КонецПроцедуры

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

&НаСервере
Функция НачатьПоискНаСервере()

	Неиспользуемые.Очистить();

	// Хранилище результата привязано к форме и живёт, пока она открыта.
	ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияФункции(УникальныйИдентификатор);
	ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Поиск неиспользуемой номенклатуры'");
	// Второй поиск, пока идёт первый, вернёт Статус = "Ошибка".
	ПараметрыВыполнения.КлючФоновогоЗадания = "ПоискНеиспользуемойНоменклатуры";

	Возврат ДлительныеОперации.ВыполнитьФункцию(ПараметрыВыполнения,
		"Обработки.ПоискНеиспользуемойНоменклатуры.НеиспользуемаяНоменклатура",
		Группа, ИсключаемыеТаблицы());

КонецФункции

&НаСервереБезКонтекста
Функция ИсключаемыеТаблицы()

	// Ссылки отсюда не делают позицию используемой: версии, штрихкоды, упаковки.
	Таблицы = Новый Массив;
	Таблицы.Добавить("РегистрСведений.ВерсииОбъектов");
	Таблицы.Добавить("РегистрСведений.ШтрихкодыНоменклатуры");
	Таблицы.Добавить("Справочник.УпаковкиЕдиницыИзмерения");

	Возврат Таблицы;

КонецФункции

&НаСервереБезКонтекста
Процедура ОтменитьЗаданиеНаСервере(Знач Идентификатор)

	ДлительныеОперации.ОтменитьВыполнениеЗадания(Идентификатор);

КонецПроцедуры

&НаКлиенте
Процедура ПоискПрогресс(Прогресс, ДополнительныеПараметры) Экспорт

	// Прогресс.Прогресс = Неопределено, если с прошлой проверки задание ничего не сообщало.
	Если Прогресс = Неопределено Или Прогресс.Прогресс = Неопределено Тогда
		Возврат;
	КонецЕсли;

	Процент = 0;
	Если Прогресс.Прогресс.Свойство("Процент", Процент) Тогда
		ПроцентВыполнения = Процент;
	КонецЕсли;
	Текст = "";
	Если Прогресс.Прогресс.Свойство("Текст", Текст) Тогда
		ТекстСостояния = Текст;
	КонецЕсли;

КонецПроцедуры

&НаКлиенте
Процедура ПоискЗавершение(Результат, ДополнительныеПараметры) Экспорт

	ИдентификаторЗадания = Неопределено;
	Элементы.ГруппаПрогресс.Видимость = Ложь;

	Если Результат = Неопределено Тогда
		Возврат; // отменили кнопкой «Прервать» или закрытием формы
	КонецЕсли;

	Если Результат.Статус = "Ошибка" Тогда
		ПоказатьПредупреждение(, Результат.КраткоеПредставлениеОшибки);
		Возврат;
	КонецЕсли;

	Найдено = ЗагрузитьРезультатНаСервере(Результат.АдресРезультата);
	ПоказатьОповещениеПользователя(НСтр("ru = 'Поиск завершён'"), ,
		СтрШаблон(НСтр("ru = 'Позиций без ссылок: %1'"), Найдено));

КонецПроцедуры

&НаСервере
Функция ЗагрузитьРезультатНаСервере(Знач Адрес)

	// ТаблицаЗначений на клиенте недоступна, поэтому хранилище читаем на сервере.
	Найденное = ПолучитьИзВременногоХранилища(Адрес);
	УдалитьИзВременногоХранилища(Адрес);
	Если ТипЗнч(Найденное) <> Тип("ТаблицаЗначений") Тогда
		Возврат 0;
	КонецЕсли;

	Неиспользуемые.Загрузить(Найденное);
	Для Каждого СтрокаСписка Из Неиспользуемые Цикл
		СтрокаСписка.Пометка = Истина;
	КонецЦикла;

	Возврат Неиспользуемые.Количество();

КонецФункции

&НаСервере
Функция НачатьПометкуНаСервере()

	Список = Новый Массив;
	Для Каждого СтрокаСписка Из Неиспользуемые Цикл
		Если СтрокаСписка.Пометка Тогда
			Список.Добавить(СтрокаСписка.Номенклатура);
		КонецЕсли;
	КонецЦикла;
	Если Список.Количество() = 0 Тогда
		Возврат Неопределено;
	КонецЕсли;

	ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияПроцедуры();
	ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Пометка неиспользуемой номенклатуры на удаление'");
	// Не ждать на сервере: окно ожидания откроется сразу и само выведет сообщения задания.
	ПараметрыВыполнения.ОжидатьЗавершение = 0;

	Возврат ДлительныеОперации.ВыполнитьПроцедуру(ПараметрыВыполнения,
		"Обработки.ПоискНеиспользуемойНоменклатуры.ПометитьНаУдаление", Список);

КонецФункции

&НаКлиенте
Процедура ПометкаЗавершение(Результат, ДополнительныеПараметры) Экспорт

	Если Результат <> Неопределено И Результат.Статус = "Ошибка" Тогда
		ПоказатьПредупреждение(, Результат.КраткоеПредставлениеОшибки);
	КонецЕсли;

	// Отмена в окне ожидания не откатывает уже помеченное, поэтому сверяемся с базой.
	УбратьПомеченныеИзСписка();

КонецПроцедуры

&НаСервере
Процедура УбратьПомеченныеИзСписка()

	Список = Новый Массив;
	Для Каждого СтрокаСписка Из Неиспользуемые Цикл
		Список.Добавить(СтрокаСписка.Номенклатура);
	КонецЦикла;

	Запрос = Новый Запрос;
	Запрос.Текст =
	"ВЫБРАТЬ
	|	Номенклатура.Ссылка КАК Ссылка
	|ИЗ
	|	Справочник.Номенклатура КАК Номенклатура
	|ГДЕ
	|	Номенклатура.Ссылка В (&Список)
	|	И Номенклатура.ПометкаУдаления";
	Запрос.УстановитьПараметр("Список", Список);

	Выборка = Запрос.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Отбор = Новый Структура("Номенклатура", Выборка.Ссылка);
		Для Каждого СтрокаСписка Из Неиспользуемые.НайтиСтроки(Отбор) Цикл
			Неиспользуемые.Удалить(СтрокаСписка);
		КонецЦикла;
	КонецЦикла;

КонецПроцедуры

#КонецОбласти

Разбор ключевых строк

ПараметрыВыполненияФункции и временное хранилище

ПараметрыВыполненияФункции(УникальныйИдентификатор) привязывает хранилище результата к форме: значение живёт, пока форма открыта, а после чтения его удаляют через УдалитьИзВременногоХранилища. Без идентификатора формы и своего АдресРезультата очищать хранилище придётся самим, а в режиме отладки БСП запишет в журнал регистрации предупреждение «Длительные операции.Диагностика». Читают результат в серверной функции формы: ТаблицаЗначений на клиенте недоступна.

Имя метода — строка: "ОбщийМодуль.Функция", "Обработки.Имя.Функция" для модуля менеджера или "Обработка.Имя.МодульОбъекта.Функция", тогда БСП сама создаст объект обработки. Параметров — до семи, значения должны сериализоваться. Вызов идёт через Вычислить(), поэтому менеджер пишут во множественном числе, как в коде самой БСП: "Обработки.ЗагрузкаДанныхИзФайла.ЗагрузитьФайлВТаблицу".

КлючФоновогоЗадания защищает от двойного запуска. Все задания длительных операций платформа видит с одним именем метода — ДлительныеОперации.ВыполнитьСКонтекстомКлиента, поэтому ключ должен быть уникален среди всех длительных операций. Повторный запуск вернёт Статус = "Ошибка" с текстом «Задание с таким значением ключа уже выполняется.». В обработке «Регламентные и фоновые задания» такое задание ищут по НаименованиеФоновогоЗадания, а не по методу.

Когда БСП не уходит в фон

После запуска сервер ждёт задание ОжидатьЗавершение секунд — по коду обеих версий 0,8 с, при низкой скорости соединения 4 с. Успело закончиться — Статус уже «Выполнено», и ОжидатьЗавершение на клиенте сразу вызывает обработчик без окна ожидания. Значение Неопределено заставит сервер ждать до конца — в форме так не делают.

Прямо в серверном вызове, без фонового задания, БСП выполняет код при запуске клиента с параметром /C РежимОтладки, при ЗапуститьНеВФоне = Истина, в файловой базе с другими активными фоновыми заданиями (если не задано ЗапуститьВФоне = Истина) и, в БСП из УТ 11.4, для внешних обработок и отчётов. Результат тогда готов сразу, а СообщитьПрогресс ничего не делает. Режим отладки флаг ЗапуститьВФоне не перекрывает.

Окно ожидания или свой индикатор

По умолчанию ВыводитьОкноОжидания = Истина: открывается форма длительной операции с текстом из ТекстСообщения, строкой «Пожалуйста, подождите...» и кнопкой «Отмена». Окно блокирует форму-владельца, с ВыводитьПрогрессВыполнения показывает процент и текст, с ВыводитьСообщения выводит сообщения задания в форму-владельца. «Отмена» отменяет задание, обработчик получает Неопределено.

С ВыводитьОкноОжидания = Ложь индикация своя: ОповещениеОПрогрессеВыполнения вызывается при каждой проверке со структурой Статус, ИдентификаторЗадания, Прогресс (Процент, Текст, ДополнительныеПараметры), Сообщения; Прогресс пуст, если задание с прошлой проверки ничего не сообщало. Закрытие формы-владельца отменяет задание. Интервал по описанию параметра растёт от 1 до 15 секунд с коэффициентом 1,4, в листинге он постоянный.

Для пометки задано ОжидатьЗавершение = 0: окно откроется сразу и само выведет сообщения по позициям. При мгновенном завершении БСП из УТ 11.4 оставила бы их только в Результат.Сообщения.

СообщитьПрогресс

Процедура работает только в фоновом задании, в остальных случаях молча выходит. В комментарии БСП рекомендовано сообщать прогресс не больше 100 раз за операцию, поэтому в листинге он отправляется только при смене целого процента. В БСП из КА 2.5 прогресс, сообщённый раньше чем через 3 секунды после предыдущего, заменяет его. ДополнительныеПараметры сериализуются в XML — передавайте простые значения.

Отмена и транзакции

ОтменитьВыполнениеЗадания откатывает только последнюю открытую транзакцию задания. Пометка пишет каждую позицию отдельно, поэтому отмена останавливает её на достигнутом месте, а уже помеченное остаётся — отсюда УбратьПомеченныеИзСписка после завершения. Нужно «всё или ничего» — пишите в одной транзакции, подробнее — в статье про транзакции в 1С.

Вариант через ВыполнитьВФоне

Более ранняя функция ВыполнитьВФоне до сих пор встречается в типовых: через неё, например, общая форма отчёта запускает ВариантыОтчетов.СформироватьОтчетВФоне. Вызываемая процедура принимает (Параметры, АдресРезультата): параметры приходят одной структурой, результат она кладёт сама. Обёртка НеиспользуемаяНоменклатураВФоне уже есть в модуле менеджера:

// Модуль формы: тот же поиск через ДлительныеОперации.ВыполнитьВФоне.
// Вызывается вместо НачатьПоискНаСервере из листинга 2, клиентская часть та же.
// Процедура НеиспользуемаяНоменклатураВФоне уже есть в модуле менеджера (листинг 1).

&НаСервере
Функция НачатьПоискЧерезВыполнитьВФоне()

	Неиспользуемые.Очистить();

	ПараметрыПроцедуры = Новый Структура;
	ПараметрыПроцедуры.Вставить("Группа", Группа);
	ПараметрыПроцедуры.Вставить("ИсключаемыеТаблицы", ИсключаемыеТаблицы());

	// С идентификатором формы БСП сама создаст адрес результата на время жизни формы.
	// Без него задайте ПараметрыВыполнения.АдресРезультата и очищайте хранилище сами.
	ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
	ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Поиск неиспользуемой номенклатуры'");
	ПараметрыВыполнения.КлючФоновогоЗадания = "ПоискНеиспользуемойНоменклатуры";

	// Процедура получит два параметра: структуру ПараметрыПроцедуры и адрес результата.
	Возврат ДлительныеОперации.ВыполнитьВФоне(
		"Обработки.ПоискНеиспользуемойНоменклатуры.НеиспользуемаяНоменклатураВФоне",
		ПараметрыПроцедуры, ПараметрыВыполнения);

КонецФункции

Клиентская часть та же. С ДополнительныйРезультат = Истина процедура получит третий параметр — адрес второго хранилища, он вернётся в АдресДополнительногоРезультата.

Типичные ошибки

  • «Недопустимое значение параметра ДлительнаяОперация в ДлительныеОперацииКлиент.ОжидатьЗавершение. Ожидалось: Структура; передано значение: Неопределено…» — серверная функция вернула Неопределено: забыли Возврат или вышли раньше, как НачатьПометкуНаСервере при пустом выборе. Проверяйте результат до вызова ОжидатьЗавершение.
  • «Если параметр ПараметрыОжидания.ВыводитьОкноОжидания установлен в Истина, то параметр ПараметрыОжидания.ОповещениеОПрогрессеВыполнения не поддерживается…» — задали своё оповещение о прогрессе и не выключили стандартное окно.
  • «Неправильный формат параметра ИмяПроцедуры (передано значение: "…") в ОбщегоНазначения.ВыполнитьМетодКонфигурации: Не существует общий модуль "…".» — опечатка в имени модуля. Текст придёт в КраткоеПредставлениеОшибки со Статус = "Ошибка".
  • «Недостаточно фактических параметров» — последним параметром ушло Неопределено. БСП отбрасывает Неопределено в конце списка Параметр1…Параметр7, и функция получает меньше параметров, чем объявлено. Дайте таким параметрам значения по умолчанию или передавайте структуру.
  • Прогресс стоит на месте. Не включили ВыводитьПрогрессВыполнения, код выполняется без фонового задания (режим отладки, файловая база с другими заданиями) или функция долго выполняет один запрос и сообщает прогресс только в конце.
  • Внешняя обработка «висит», как без БСП. В БСП из УТ 11.4 методы "ВнешняяОбработка.Имя.МодульОбъекта.Метод" выполняются без фонового задания, а в БСП из КА 2.5 без двоичных данных обработки в ПараметрыВыполнения.ВнешнийОтчетОбработка будет ошибка «Для вызова процедуры внешнего отчета или внешней обработки требуется заполнить параметр ВнешнийОтчетОбработка». Подробнее о таких обработках — в статье о внешней обработке 1С.

Частые вопросы

Чем ВыполнитьФункцию отличается от ВыполнитьВФоне?

ВыполнитьФункцию запускает любую экспортную функцию с параметрами до семи и сама кладёт её результат во временное хранилище. ВыполнитьВФоне требует процедуру (Параметры, АдресРезультата). В коде БСП к ВыполнитьВФоне написано, что вместо неё рекомендуется использовать ВыполнитьФункцию и ВыполнитьПроцедуру.

Как отладить код длительной операции?

Запустите клиент с параметром /C РежимОтладки: БСП выполнит операцию прямо в серверном вызове, и точки останова сработают как в обычном коде. Отладку самого фонового задания включают в конфигураторе, см. отладку на сервере 1С.

Что будет, если закрыть форму во время операции?

Стандартное окно ожидания блокирует форму, а «Отмена» отменяет задание. При своём индикаторе БСП сама отменяет задание, когда закрывается форма-владелец; в БСП из КА 2.5 это выключается свойством ОтменятьПриЗакрытииФормыВладельца. Результат, привязанный к идентификатору формы, после её закрытия всё равно не прочитать.

Как передать больше семи параметров или данные формы?

Соберите их в Структура и передайте одним параметром. Данные формы сначала превратите в обычные значения: таблицу — через Выгрузить() или РеквизитФормыВЗначение, так делает сама БСП в форме удаления помеченных объектов. Форму, объект обработки или менеджер временных таблиц передать нельзя: значения должны сериализоваться.

Когда проще заказать

Если операция подвешивает пользователей, а переводить её на длительные операции с прогрессом, отменой и защитой от двойного запуска некогда, отдайте задачу программисту: раздел «1С тормозит» и другие услуги по доработке 1С. Опишите, какая операция и в какой конфигурации выполняется долго, на странице «Разместить задание» — оценка бесплатная, ответ в течение рабочего дня.

По теме

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.


1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.