В процессе разработки в системе 1С:Предприятие 8.3 часто возникает необходимость не просто прервать выполнение регламентного задания, а зафиксировать его аварийное завершение. Это критично, когда мы полагаемся на платформенный механизм «повторять при ошибке», заданный в настройках расписания. Если регламентное задание просто завершает работу (даже если данные не были обработаны), платформа считает его выполненным успешно, и следующий запуск произойдет только согласно основному графику.
Разберем ситуацию, когда стандартная команда ВызватьИсключение не приводит к желаемому результату, и выясним, как заставить систему корректно регистрировать ошибку или использовать более надежные методы управления повторами.
Проанализируем механику работы фоновых заданий, которые инициируются регламентными. Когда мы пишем код в модуле объекта или общем модуле, вызываемом заданием, мы ожидаем, что любое необработанное исключение «уронит» поток. Однако на практике статус задания часто остается «Выполнено», разобраться в причинах поможет справочник по методам БСП.
Основная причина кроется в использовании Библиотеки стандартных подсистем (БСП) или наличии внешних обработчиков. В современных конфигурациях выполнение регламентного задания часто оборачивается в глобальный блок Попытка...Исключение на уровне системных механизмов (например, в процедурах очереди заданий). В этом случае:
Рассмотрим подробнее, как обойти это поведение и какие альтернативы существуют (включая внешний регламент для 1С, работающий вне рамок БСП).
Первым делом проанализируем стек вызовов. Если внутри вашей обработки или в общих модулях, к которым она обращается, есть пустые или недостаточно информативные блоки перехвата ошибок, исключение просто «поглощается».
Посмотрим на пример кода, который не позволит заданию завершиться аварийно:
Процедура ВыполнитьЗагрузкуДанных() Экспорт
Попытка
// Логика получения данных
Если Данные.Количество() = 0 Тогда
ВызватьИсключение "Данные не найдены";
КонецЕсли;
Исключение
// Здесь ошибка перехвачена, но никак не проброшена выше
ЗаписатьВЖурналРегистрации("Загрузка", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Чтобы задание завершилось со статусом «Ошибка», необходимо либо убрать блок Попытка...Исключение, либо повторно вызвать исключение внутри блока Исключение с помощью ключевого слова ВызватьИсключение без параметров:
Исключение
ЗаписатьВЖурналРегистрации("Загрузка", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
ВызватьИсключение; // Пробрасываем ошибку на уровень платформы
КонецПопытки;
В платформе 8.3.23 и выше появился расширенный синтаксис исключений с категориями. Выясним, как это влияет на регламентные задания. Если вы используете КатегорияОшибки.ОшибкаВнешнегоИсточникаДанных, платформа может интерпретировать это как некритичную ошибку связи, которую не всегда нужно фиксировать как крах процесса.
Попробуем использовать максимально простой и жесткий вариант вызова ошибки, который гарантированно должен прервать выполнение:
Если Данные.Количество() = 0 Тогда
// Используем классический вариант без дополнительных параметров
ВызватьИсключение "Критическая ошибка: Данные из внешней базы не получены!";
КонецЕсли;
Если даже это не помогает, можно прибегнуть к «грязному», но действенному методу — вызвать системную ошибку исполнения, например, деление на ноль, но только в целях отладки, чтобы убедиться, что проблема не в логике 1С, а в перехвате исключений системой.
Если ваша цель — не просто увидеть красную надпись в консоли, а обеспечить гарантированное получение данных, рассмотрим более надежный архитектурный подход. Вместо того чтобы полагаться на аварийное завершение, создадим механизм контроля даты следующего запуска.
Выполним следующие шаги:
ДатаСледующейЗагрузки (тип Дата).Проанализируем пример реализации:
Процедура ВыполнитьРегламентноеЗадание() Экспорт
// Проверяем, пришло ли время работать
Если ТекущаяДата() < Константы.ДатаСледующейЗагрузки.Получить() Тогда
Возврат; // Задание завершается успешно, ничего не делая
КонецЕсли;
Данные = ПолучитьДанныеИзВнешнейБазы();
Если Данные.Количество() > 0 Тогда
ОбработатьДанные(Данные);
// Если все ок, планируем запуск на 1-е число следующего месяца
НоваяДата = НачалоМесяца(ДобавитьМесяц(ТекущаяДата(), 1));
Константы.ДатаСледующейЗагрузки.Установить(НоваяДата);
Иначе
// Данных нет. Константу не обновляем.
// Задание запустится снова согласно расписанию (например, завтра)
ЗаписатьВЖурналРегистрации("Загрузка", УровеньЖурналаРегистрации.Предупреждение,,, "Данных нет, повторим позже");
КонецЕсли;
КонецПроцедуры
Преимущество этого метода: Вы полностью контролируете логику. Задание всегда имеет статус «Выполнено», Журнал регистрации остается чистым от ложных «аварий», а бизнес-логика соблюдается безукоризненно.
Рассмотрим продвинутый вариант. Если данные не получены, мы можем прямо из кода изменить расписание самого регламентного задания. Это позволяет реализовать гибкую стратегию: например, «если данных нет — проверить через 15 минут, если есть — установить запуск на следующий месяц».
Для этого используется объект РегламентныеЗадания. Посмотрим на пример кода:
МетаданныеЗадания = Метаданные.РегламентныеЗадания.ЗагрузкаИзВнешнейБазы;
Задание = РегламентныеЗадания.НайтиПоМетаданным(МетаданныеЗадания)[0];
Если ДанныеПолучены Тогда
// Устанавливаем расписание: Раз в месяц, 1-го числа
НовоеРасписание = Новый РасписаниеРегламентногоЗадания;
НовоеРасписание.ПериодичностьЗавершенияВТечениеДня = 0;
НовоеРасписание.ДеньВМесяце = 1;
Задание.Расписание = НовоеРасписание;
Задание.Записать();
Иначе
// Устанавливаем расписание: Повторять каждые 30 минут, пока не получим данные
НовоеРасписание = Новый РасписаниеРегламентногоЗадания;
НовоеРасписание.ПериодичностьПовтораВТечениеДня = 1800;
Задание.Расписание = НовоеРасписание;
Задание.Записать();
КонецЕсли;
Этот метод требует прав на управление регламентными заданиями у пользователя, под которым запускается фоновый процесс (обычно это учетная запись сервера 1С), но он является наиболее «профессиональным» с точки зрения эксплуатации системы.
Мы выяснили, что отсутствие статуса «Ошибка» при вызове исключения чаще всего связано с перехватом этого исключения в вышестоящих модулях (особенно в типовых конфигурациях на базе БСП). Для решения задачи рекомендуем следующее:
Попытка...Исключение в цепочке вызовов и убедитесь, что исключение пробрасывается на самый верхний уровень.ВызватьИсключение внутри транзакции может привести к откату всех изменений в базе данных, сделанных в рамках этого задания.Выбор конкретного метода зависит от того, насколько критично для вас видеть статус «Ошибка» в стандартной консоли регламентных заданий. Для стабильных промышленных систем использование управляемой логики (через даты запуска) всегда предпочтительнее, чем использование механизмов аварийного завершения.