Как реализовать оповещение о ходе выполнения длительной операции с сервера на клиент?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки на платформе 1С:Предприятие 8.3 часто возникает классическая задача: необходимо выполнить длительную обработку данных на сервере и при этом информировать пользователя о текущем состоянии процесса в режиме реального времени. Если запустить процедуру обычным способом, интерфейс программы «зависает» до завершения выполнения, и пользователь не видит никакой обратной связи. В этой статье мы разберем современные и надежные способы решения этой задачи, от стандартных механизмов БСП до использования Системы взаимодействия.

Почему стандартный синхронный вызов не подходит

Рассмотрим ситуацию, представленную в исходном вопросе. Когда мы вызываем серверную процедуру ПометитьНаУдаление() напрямую из клиентской команды, происходит блокировка основного потока интерфейса. Пока сервер не закончит перебор всех контрагентов и не вернет управление клиенту, форма не будет перерисована. Любые попытки вызвать внутри такого цикла метод Состояние() или обновить реквизиты формы не дадут визуального эффекта до самого конца операции. Для решения этой проблемы нам необходимо перевести операцию в асинхронный режим.

Решение №1: Использование фоновых заданий и обработчика ожидания

Разберем самый распространенный технический подход. Суть его заключается в том, что длительная операция запускается в отдельном потоке (фоновом задании), а клиентская форма периодически «опрашивает» сервер о состоянии этого задания.

Для реализации этого механизма выполним следующие шаги:

  1. Запуск фонового задания: На сервере вызываем метод ФоновыеЗадания.Выполнить(), передавая имя нашей экспортной процедуры и параметры.
  2. Использование временного хранилища: Чтобы передавать данные о прогрессе (например, процент выполнения), фоновое задание должно записывать структуру данных во временное хранилище по уникальному адресу.
  3. Клиентский цикл опроса: На клиенте подключаем обработчик ожидания через метод ПодключитьОбработчикОжидания().

Посмотрим на пример реализации кода для серверной части:


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

Проанализируем работу фонового задания. Внутри процедуры ВыполнитьДлительнуюОперацию мы должны периодически обновлять данные в хранилище:


Процедура ВыполнитьДлительнуюОперацию(Параметры, АдресРезультата) Экспорт
    Выборка = Справочники.Контрагенты.Выбрать();
    Всего = Выборка.Количество();
    Счетчик = 0;
    
    Пока Выборка.Следующий() Цикл
        // Основная логика
        Счетчик = Счетчик + 1;
        
        // Обновляем прогресс каждые 10 итераций для экономии ресурсов
        Если Счетчик % 10 = 0 Тогда
            Прогресс = (Счетчик / Всего) * 100;
            ПоместитьВоВременноеХранилище(Прогресс, АдресРезультата);
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

Решение №2: Использование подсистемы «Длительные операции» из БСП

Если ваша конфигурация построена на базе Библиотеки стандартных подсистем (БСП), крайне рекомендуется использовать встроенный модуль ДлительныеОперации. Это «кошерный» способ, который уже содержит все необходимые механизмы обработки ошибок и управления сеансами.

Рассмотрим основные преимущества использования БСП:

  1. Стандартизация: Вам не нужно изобретать велосипед с обработчиками ожидания.
  2. Метод СообщитьПрогресс: БСП предоставляет удобную обертку для передачи текстовых сообщений и процентов на клиент.
  3. Готовые формы: Можно использовать стандартную форму прогресса, которая блокирует ввод пользователя, но показывает живой индикатор.

Для реализации через БСП мы используем функцию ДлительныеОперации.ЗапуститьВыполнениеНаСервере(). На клиенте выполнение контролируется через процедуру ДлительныеОперацииКлиент.ОжидатьЗавершения(). Это позволяет реализовать сценарий, когда пользователь видит модальное окно с прогресс-баром и кнопкой отмены.

Решение №3: Система взаимодействия (Push-уведомления)

Выясним причину, по которой этот метод считается наиболее современным. В отличие от предыдущих способов, где клиент «тянет» данные с сервера (Pull), Система взаимодействия позволяет серверу самому «толкать» данные на клиент (Push) через протокол WebSocket.

Проанализируем шаги для внедрения этого метода:

Этот метод идеален, если операция очень длительная (например, занимает несколько часов). Пользователь может закрыть форму или даже программу, а при получении уведомления от системы взаимодействия он увидит всплывающее окно в углу экрана, когда задача будет завершена.

Механизм «ПолучитьСообщенияПользователю»

Рассмотрим еще один важный нюанс, упомянутый в обсуждении. При работе фонового задания стандартный метод Сообщить() не выводит текст в окно сообщений пользователя немедленно. Все сообщения накапливаются в буфере фонового задания.

Чтобы их прочитать, при опросе состояния задания из обработчика ожидания необходимо вызвать метод ПолучитьСообщенияПользователю(Истина). Параметр Истина важен, так как он очищает прочитанные сообщения, чтобы при следующем вызове вы получили только новые порции лога. Это отличный способ реализовать текстовый лог выполнения операции в реальном времени.

Рекомендации по выбору метода

Подводя итог, выберем оптимальный путь в зависимости от ваших условий:

Помните, что ключевым моментом любого решения является вынос кода из основного потока формы в фоновый процесс. Это сохраняет отзывчивость интерфейса и повышает удобство работы пользователя с программой.

← На главную