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