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

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

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

Почему стандартная команда ОбработкаПрерыванияПользователя() не всегда помогает?

Проанализируем работу стандартного метода ОбработкаПрерыванияПользователя(). В обычном приложении или при выполнении кода на стороне клиента этот метод реагирует на нажатие комбинации клавиш Ctrl+Break. Если система фиксирует нажатие, генерируется исключение, и выполнение кода прекращается. Однако при серверном вызове ситуация меняется:

  1. Интерфейс «висит», и нажатия клавиш не передаются серверу в реальном времени.
  2. Серверный поток не знает о состоянии клавиатуры пользователя.
  3. Если код выполняется не в фоновом задании, то остановить его можно только принудительно через консоль администратора или закрыв клиентское приложение (что не гарантирует немедленной остановки серверного процесса).

Рассмотрим по шагам основные стратегии решения этой проблемы.

Решение 1: Использование фоновых заданий и механизмов БСП

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

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

Посмотрим на пример кода, который должен быть размещен в теле цикла на сервере внутри фонового задания:


Для Каждого СтрокаДанных Из МассивОбъектов Цикл
    // Выполняем полезную работу
    ОбработатьОбъект(СтрокаДанных);
    
    // Проверяем, не пришло ли требование на отмену
    ОбработкаПрерыванияПользователя();
КонецЦикла;

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

Решение 2: Обработка данных порциями (Клиент-Серверный цикл)

Если по каким-то причинам использование фоновых заданий невозможно или нецелесообразно, проанализируем метод обработки данных «порциями». Суть заключается в том, что основной цикл перебора объектов выполняется на клиенте, а на сервер передается только одна порция данных для обработки.

Рассмотрим пример реализации такой логики:


&НаКлиенте
Процедура ВыполнитьОбработку()
    МассивДанных = ПолучитьСписокДанныхДляОбработки();
    
    Для Каждого Элемент Из МассивДанных Цикл
        // Проверяем нажатие Ctrl+Break на клиенте
        ОбработкаПрерыванияПользователя();
        
        // Передаем данные на сервер по одному или пачками
        ОбработатьНаСервере(Элемент);
        
        // Можно обновить индикатор на форме
        Состояние("Обработано: " + Элемент.Наименование);
    КонецЦикла;
КонецПроцедуры

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

Решение 3: Использование внешнего флага прерывания (Временное хранилище)

Иногда требуется прервать цикл, который невозможно вынести в фоновое задание или разбить на клиентские порции. В этом случае можно использовать механизм «сигнального флага» через Временное хранилище или, в крайнем случае, через Регистр сведений.

Разберем алгоритм работы через временное хранилище:

  1. Перед запуском процесса создаем уникальный идентификатор (UUID) и помещаем в хранилище значение Ложь (флаг отмены).
  2. Передаем этот UUID в серверную процедуру.
  3. На форме создаем кнопку «Прервать», которая по нажатию записывает во временное хранилище по этому UUID значение Истина.
  4. Внутри серверного цикла периодически проверяем это значение.

Посмотрим на реализацию проверки в цикле:


&НаСервереБезКонтекста
Процедура ДлительныйЦиклНаСервере(КлючОтмены)
    Счетчик = 0;
    Пока Истина Цикл
        // Основная логика
        Счетчик = Счетчик + 1;
        
        // Чтобы не нагружать систему проверками, проверяем флаг раз в 100 итераций
        Если Счетчик % 100 = 0 Тогда
             ФлагОтмены = ПолучитьИзВременногоХранилища(КлючОтмены);
             Если ФлагОтмены = Истина Тогда
                 Прервать; // Или ВызватьИсключение "Операция отменена пользователем"
             КонецЕсли;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

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

Проблема незавершенных транзакций

Проанализируем ситуацию с данными при прерывании. Если ваш цикл обернут в общую транзакцию с помощью команд НачатьТранзакцию() и ЗафиксироватьТранзакцию(), то любое прерывание (будь то программное исключение или отмена фонового задания) приведет к полному откату всех изменений. В базе данных не останется «следов» частично выполненной работы.

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

Рекомендации для Веб-клиента

Выясним особенности работы в браузере. В веб-клиенте комбинация Ctrl+Break часто перехватывается самим браузером или попросту не работает. Поэтому для решений, ориентированных на работу через веб-интерфейс, использование фоновых заданий (Решение 1) является единственным надежным промышленным стандартом. Пользователь должен иметь явную кнопку «Отмена» на форме, которая через серверный вызов прекратит выполнение фонового потока.

Заключение

Мы рассмотрели различные методы управления серверными циклами. Выбор конкретного метода зависит от архитектуры вашей конфигурации. Для простых обработок в небольших базах подойдет обработка порциями на клиенте. Для крупных корпоративных систем и облачных решений (SaaS) единственно верным путем будет использование фоновых заданий с контролем состояния через ОбработкаПрерыванияПользователя().

← На главную