Как прервать выполнение длительной процедуры на сервере в 1С при загрузке данных?

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

При обработке больших объемов данных (например, при загрузке прайс-листов на 80 000 позиций) разработчики 1С часто сталкиваются с ситуацией, когда процедура на сервере выполняется слишком долго, а пользователь теряет контроль над процессом. Попытка вызвать интерактивные методы или обработать нажатие кнопки прямо во время исполнения серверного кода приводит к ошибкам. Разберем подробнее, почему так происходит, какие существуют технические ограничения платформы и как правильно организовать управляемый выход из длительной процедуры.

Почему нельзя прервать серверную процедуру «напрямую»

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

Также важно помнить об ограничениях контекста:

  1. Метод ОбработкаПрерыванияПользователя() доступен только в клиентских контекстах (тонкий клиент, веб-клиент, толстый клиент). Вызов этой функции на сервере вызовет ошибку компиляции или выполнения.
  2. На сервере отсутствует понятие пользовательского интерфейса. Серверный контекст ничего не знает о состоянии формы или нажатых кнопках на клиенте, пока текущий вызов не завершится целиком.

Вариант 1. Запуск обработки в фоне (асинхронный подход)

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

Рассмотрим пошаговый алгоритм реализации этого метода:

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

Проанализируем пример схемы работы фонового задания с использованием Библиотеки Стандартных Подсистем (БСП):


&НаКлиенте
Процедура ЗапуститьЗагрузку(Команда)
    ПараметрыПроцедуры = Новый Структура("ПутьКФайлу", ПутьКФайлу);
    ДлительнаяОперация = ВыполнитьЗагрузкуВФонеНаСервере(ПараметрыПроцедуры);
    
    // Подключаем опрос состояния
    ПодключитьОбработчикОжидания("ПроверитьЗавершениеЗагрузки", 2);
КонецПроцедуры

&НаСервере
Функция ВыполнитьЗагрузкуВФонеНаСервере(ПараметрыПроцедуры)
    Возврат ДлительныеОперации.ВыполнитьВФоне("МойМодуль.ЗагрузитьПрайсЛист", ПараметрыПроцедуры);
КонецФункции

&НаКлиенте
Процедура ОтменитьЗагрузку(Команда)
    ОтменитьЗаданиеНаСервере(ИдентификаторЗадания);
    ОтключитьОбработчикОжидания("ПроверитьЗавершениеЗагрузки");
    Сообщить("Загрузка прервана пользователем.");
КонецПроцедуры

Вариант 2. Порционная обработка данных на клиенте

Если нет возможности использовать фоновые задания, разберем альтернативный способ — порционную обработку. Суть метода заключается в том, что массив данных разбивается на небольшие блоки (например, по 500–1000 строк), и управление периодически возвращается на клиент.

Проанализируем алгоритм работы:

  1. Файл с данными считывается в таблицу на клиенте или сервер возвращает клиенту общую структуру данных.
  2. Цикл обработки выполняется на клиенте и передает на сервер порцию из N элементов.
  3. В цикле на клиенте вызывается метод ОбработкаПрерыванияПользователя(), который отслеживает нажатие комбинации клавиш Ctrl + Break или нажатие кнопки отмены.
  4. Если прерывание не зафиксировано, на сервер отправляется следующая порция записей.

Посмотрим на пример организации порционного вызова:


&НаКлиенте
Процедура ОбработатьПорциями()
    ВсегоСтрок = МассивДанных.Количество();
    РазмерПорции = 1000;
    Индекс = 0;
    
    Пока Индекс < ВсегоСтрок Цикл
        // Проверяем, не нажал ли пользователь отмену
        ОбработкаПрерыванияПользователя();
        
        // Формируем порцию для отправки на сервер
        Порция = ПолучитьПорцию(МассивДанных, Индекс, РазмерПорции);
        ОбработатьПорциюНаСервере(Порция);
        
        Индекс = Индекс + РазмерПорции;
    КонецЦикла;
КонецПроцедуры

Вариант 3. Использование флага остановки в информационной базе

Еще один вариант взаимодействия с длительной процедурой — использование промежуточного хранилища состояний (константы, регистра сведений или хранилища настроек). Процедура на сервере в цикле периодически проверяет значение флага (например, каждые 500 элементов). Если флаг установлен в значение Истина, серверный процесс корректно завершает работу через оператор Прервать или Возврат. Установка самого флага отмены при этом выполняется из другого сеанса.

Причины низкой скорости и методы оптимизации загрузки

Выполнение загрузки 80 000 строк в течение 9 часов указывает на узкие места в алгоритме обработки данных. Посмотрим, за счет чего можно сократить время выполнения в десятки раз:

  1. Отказ от COM-объекта Excel: Чтение через Excel.Application работает крайне медленно и потребляет много ресурсов. Для чтения XLSX-файлов эффективнее использовать ЧтениеXML, метод ТабличныйДокумент.Прочитать() или выгрузку в формат CSV с последующим чтением через ЧтениеТекста.
  2. Отключение бизнес-логики: При запись справочников устанавливайте свойство Объект.ОбменДанными.Загрузка = Истина. Это отключает лишние проверки и подписки на события при массовом создании объектов.
  3. Групповая запись в регистры: Вместо построчного использования объекта МенеджерЗаписи применяйте РегистрСведенийНаборЗаписей. Формируйте набор на группу элементов и записывайте его целиком.
  4. Использование транзакций: Оборачивайте запись каждых 500–1000 элементов в блоки НачатьТранзакцию() ... ЗафиксироватьТранзакцию(). Это кардинально снижает количество обращений к СУБД на запись дисковых данных.
← На главную