Как продолжить работу цикла при возникновении критической ошибки при перепроведении документов?

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

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

Анализ основной ошибки: Неправильное использование блока Исключение

Разберем ситуацию, когда стандартная конструкция Попытка ... Исключение не спасает от остановки цикла. Проанализируем код, который часто становится причиной проблемы:


Пока Выборка.Следующий() Цикл
    НачатьТранзакцию();
    ТекОбъект = Выборка.Ссылка.ПолучитьОбъект();
    Попытка
        ТекОбъект.Записать(РежимЗаписиДокумента.Проведение);
        ЗафиксироватьТранзакцию();
    Исключение
        // Вот здесь кроется главная ошибка
        Сообщить("Проблема в проведении: " + Выборка.Ссылка);
        ВызватьИсключение; 
    КонецПопытки;
КонецЦикла;

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

Управление транзакциями: Избегаем "битых" транзакций

Одной из скрытых причин остановки циклов является некорректная работа с транзакциями. Рассмотрим механизм: если внутри транзакции (после НачатьТранзакцию) происходит ошибка, транзакция помечается системой как "битая". В таком состоянии любая попытка зафиксировать её или начать новую транзакцию приведет к системной ошибке "В данной транзакции уже происходили ошибки".

Разберем по шагам правильную структуру кода с учетом транзакций:

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

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


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

Подавление интерактивных окон через ОбменДанными.Загрузка

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

Проанализируем ситуацию: когда вы устанавливаете свойство ТекОбъект.ОбменДанными.Загрузка = Истина, типовые механизмы 1С (в процедурах ПередЗаписью, ПриЗаписи, ОбработкаПроверкиЗаполнения) понимают, что данные записываются программно (например, при обмене или массовой обработке), и пропускают большинство интерактивных проверок.

Применим это в нашем коде:


ТекОбъект = Выборка.Ссылка.ПолучитьОбъект();
ТекОбъект.ОбменДанными.Загрузка = Истина; 
Попытка
    ТекОбъект.Записать(РежимЗаписиДокумента.Проведение);
Исключение
    // Обработка ошибки
КонецПопытки;

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

Выполнение в фоновом задании на сервере

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

Рассмотрим преимущества этого подхода:

Использование Журнала регистрации вместо метода Сообщить

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

Пример использования ЗаписьЖурналаРегистрации:


Исключение
    ЗаписьЖурналаРегистрации("МассовоеПроведение",
        УровеньЖурналаРегистрации.Ошибка,
        ТекОбъект.Метаданные(),
        ТекОбъект.Ссылка,
        "Ошибка: " + ОписаниеОшибки());
КонецПопытки;

Профилактика критических сбоев платформы

Существуют "неуловимые" ошибки, которые Попытка не сможет обработать. К ним относятся: потеря соединения с сервером БД, критическая нехватка памяти (Out of Memory) или сбои в структуре таблиц. В этих случаях выполнение прервется вместе с сеансом.

Для минимизации последствий таких сбоев рекомендуем:

  1. Обрабатывать документы порциями (например, по 500-1000 штук) в рамках отдельных транзакций.
  2. Логировать прогресс выполнения (записывать ссылку на последний успешно обработанный документ в отдельный файл или константу), чтобы в случае вылета можно было продолжить с того же места.
  3. Отключать в настройках конфигуратора опцию "Останавливаться по ошибке" во время выполнения массовых операций, иначе отладчик будет перехватывать даже те исключения, которые находятся внутри блока "Попытка".

Соблюдение этих правил позволит вам создать отказоустойчивый скрипт для перепроведения документов даже в самых сложных и запущенных базах данных.

← На главную