О вложенных попытках, исключениях и о представлении ошибок

07.11.21

Разработка - Механизмы платформы 1С

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

Вопрос знатокам: какое сообщение будет выведено пользователю после выполнения данного кода?

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

&НаСервере
Процедура ВызватьОшибкуБезВызоваИсключенияНаСервере()
	
	Попытка
		А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();
	Исключение
	КонецПопытки;
	
КонецПроцедуры

Логично предположить, что это будет что-то вроде "Недостаточно фактических параметров". Но на самом деле сообщение вообще не будет выведено.

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

Как исправить? Достаточно просто: нужно лишь добавить оператор ВызватьИсключение во вложенную попытку, например, вот так:

&НаСервере
Процедура ВызватьОшибкуБезВызоваИсключенияНаСервере()
	
	Попытка
		А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();
	Исключение
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

Теперь давайте разберемся в том, какие описания ошибок будут возникать. В следующем примере, в комментарии после каждой переменной, привожу содержимое этой переменной:

&НаКлиенте
Процедура ВызватьОшибку(Команда)
	
	Попытка
		ВызватьОшибкуНаСервере();
	Исключение
		Описание = ОписаниеОшибки();
		// {ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма(20)}: Не удалось получить значение реквизита по причине: {ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма(6)}: Недостаточно фактических параметров
		
		Информация = ИнформацияОбОшибке();
		
		КраткоеПредставление = КраткоеПредставлениеОшибки(Информация);
		// Не удалось получить значение реквизита по причине: {ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма(6)}: Недостаточно фактических параметров
		
		ПодробноеПредставление = ПодробноеПредставлениеОшибки(Информация);
		// Не удалось получить значение реквизита по причине: {ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма(6)}: Недостаточно фактических параметров
		// {ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма(20)}:		ВызватьИсключение "Не удалось получить значение реквизита по причине: " + Описание;
		// {ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма(29)}:		ВызватьОшибкуНаСервере();
		
		ОбщегоНазначенияКлиентСервер.СообщитьПользователю(КраткоеПредставление);
		// Не удалось получить значение реквизита по причине: {ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма(30)}: Недостаточно фактических параметров
	КонецПопытки;
	
КонецПроцедуры

&НаСервере
Процедура ВызватьОшибкуНаСервере()
	
	Попытка
		А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();
	Исключение
		Описание = ОписаниеОшибки();
		// {ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма(6)}: Недостаточно фактических параметров
		
		Информация = ИнформацияОбОшибке();
		// Информация.ИмяМодуля = "ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма"
		// Информация.ИсходнаяСтрока = "		А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();"
		// Информация.НомерСтроки = 30
		// Информация.Описание = "Недостаточно фактических параметров"
		// Информация.Причина = Неопределено
		
		КраткоеПредставлениеОшибки(Информация);
		// Недостаточно фактических параметров
		
		ПодробноеПредставлениеОшибки(Информация);
		// Недостаточно фактических параметров
		// {ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма(6)}:		А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();
		
		ВызватьИсключение "Не удалось получить значение реквизита по причине: " + Описание;
	КонецПопытки;
	
КонецПроцедуры

 

Попытка Исключение ВызватьИсключение ОписаниеОшибки ИнформацияОбОшибке КраткоеПредставлениеОшибки ПодробноеПредставлениеОшибки ОбщегоНазначения ОбщегоНазначенияКлиентСервер СообщитьПользователю

См. также

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

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

23.06.2024    7522    bayselonarrend    20    

154

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример использования «Сервисов интеграции» без подключения к Шине и без обменов.

13.03.2024    5970    dsdred    16    

80

Механизмы платформы 1С Программист Стажер Платформа 1С v8.3 Бесплатно (free)

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

24.01.2024    17840    YA_418728146    26    

71

Механизмы платформы 1С Программист Бесплатно (free)

Язык программирования 1С содержит много нюансов и особенностей, которые могут приводить к неожиданным для разработчика результатам. Сталкиваясь с ними, программист начинает лучше понимать логику платформы, а значит, быстрее выявлять ошибки и видеть потенциальные узкие места своего кода там, где позже можно было бы ещё долго медитировать с отладчиком в поисках источника проблемы. Мы рассмотрим разные примеры поведения кода 1С. Разберём результаты выполнения и ответим на вопросы «Почему?», «Как же так?» и «Зачем нам это знать?». 

06.10.2023    23789    SeiOkami    48    

135

WEB-интеграция Универсальные функции Механизмы платформы 1С Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    14789    YA_418728146    7    

166
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. sapervodichka 6915 08.11.21 16:27 Сейчас в теме
+1 за публикацию. Я не ради маркетинга тут ссылку запилю, только ради интереса к теме. Вот пример как вешал условие-костыль на стек вызова в попытке исключении https://infostart.ru/1c/articles/1263068/
Enziger; ivnik; +2 Ответить
2. Nicholas 902 08.11.21 16:34 Сейчас в теме
(1) Интересный прием. Спасибо.
sapervodichka; +1 Ответить
3. Serg O. 297 09.11.21 08:58 Сейчас в теме
вложенные попытка в попытке работают... https://forum.infostart.ru/forum9/topic4264/
но не везде
в транзакциях, например, попытка в попытке не работает
в попытке в процедуре ПриЗаписи (которая идёт в транзакции записи 1 документа)
- попытка записать другой документ - не сработает, наверное
должно выкинуть на исключение первой попытки.
подробнее на ИТС https://its.1c.ru/db/v8std/content/499/hdoc
Nicholas; +1 Ответить
4. kuzyara 2091 09.11.21 12:46 Сейчас в теме
наболело)
очень часты случаи когда в попытку запихивают вообще всё подряд
вот пример из последнего код-ревью
// где-то в конце процедуры
				Попытка
				
					МЗ = РегистрыСведений.СтратегииВизитовПоМенеджерам.СоздатьМенеджерЗаписи();
					МЗ.Менеджер = Выборка.Менеджер;
					МЗ.Стратегия = Выборка.Стратегия;
					
					Если Результат.Успех Тогда
						
						МЗ.Обработано = Истина;
						МЗ.ОписаниеОшибки = "";
						
					Иначе
						
						МЗ.Обработано = Ложь;
						МЗ.ОписаниеОшибки = Результат.ОписаниеОшибки;
						
					КонецЕсли;

					МЗ.Записать();
					
				Исключение
					ЗаписьЖурналаРегистрации("РаспределениеГрафикаВизитов", УровеньЖурналаРегистрации.Ошибка, , , "Не удалось записать стратегию визитов по менеджеру. " + ОписаниеОшибки());
				КонецПопытки;
Показать

Спрашиваю: какая здесь возникает ошибка? мб попытка здесь лишняя?
ответ: ну вдруг блокировка или ошибка записи

или условно вот такой кейс
Попытка
	ВыполнитьАлгоритмРасчета();
Исключение
	ЗаписьЖурналаРегистрации("Ошибка <ИмяАлгоритма>", УровеньЖурналаРегистрации.Ошибка, , , "Не удалось выполнить <ОписаниеОсобоВажнойПроцедуры> " + ОписаниеОшибки());
КонецПопытки;

прячем под ковёр потенциальные ошибки... типа в основном всё работает, но иногда может и нет?

В чем прикол таких попыток? На "всякий случай"?

Объясните...
DrAku1a; Dnki; artbear; +3 Ответить
6. artbear 1563 09.11.21 14:01 Сейчас в теме
(4) сразу же скажу, что так в ЖР писать нельзя
Исключение
    ЗаписьЖурналаРегистрации("Ошибка <ИмяАлгоритма>", УровеньЖурналаРегистрации.Ошибка, , , "Не удалось выполнить <ОписаниеОсобоВажнойПроцедуры> " + ОписаниеОшибки());
КонецПопытки;


нельзя передавать ОписаниеОшибки() или КраткоеПредставлениеОшибки

теряется стек вызовов, нужно обязательно передавать ПодробноеПредставлениеОшибки

в стандарте 1С https://its.1c.ru/db/v8std/content/499/hdoc об этом написано.

Есть правило стат.анализа в БСЛ ЛС\плагине для СонарКуб, которое отлавливает эту проблему.
Nicholas; +1 Ответить
7. artbear 1563 09.11.21 14:11 Сейчас в теме
(4) На самом деле в приведенном коде ошибки не совсем прячутся, конечно.
Особенно, если запись в ЖР выполнена верно, как я написал в (6)

Такой код может юзаться, если есть последующие шаги алгоритма\логики, которые должны выполняться даже в случае промежуточной ошибки.

ИМХО в подобных блоках попыток есть минус, если указанный код выполняется пользователем или тем же администратором\разработчиком.
в этом случае пользователь не увидит сообщения об ошибке.

например, создается некая утилита в виде внешней обработки, которая выполняет какие административные действия и запускается админом.
И разработчики сохраняют ошибки в ЖР, но забывают, что человеку становится сложно\непонятно, были ли ошибки, какие ошибки были, какие проблемы виноваты и т.п.
9. TMV 14 10.11.21 09:15 Сейчас в теме
(4)Что, если прав не хватает на регистр?
16. glek 120 16.12.21 08:13 Сейчас в теме
(4) Объясняю: есть работающая база, которая обновляется строго по расписанию. Динамически обновлять нельзя. Расширения использовать нельзя, по причине низкой совместимости. Поднять совместимость до приемлемого уровня нельзя по причине древности базы.
И что делать в таком случае? Только обрамлять в попытку.
17. Nicholas 902 16.12.21 08:18 Сейчас в теме
(16) Согласен. Есть ситуации, когда без "попытки" не обойтись.
5. artbear 1563 09.11.21 13:57 Сейчас в теме
(0) Отличная расшифровка. Спасибо.

Я уточню только один момент!

Опасно использовать конструкцию
ВызватьИсключение КакойТоТекст;

Причины:
- можно полностью или частично потерять стек вызовов
- полная потеря, если в строку не передать данные о возникшей ошибке
- частичная потеря, если к строке добавить ОписаниеОшибки(), как у тебя, или КраткоеПредставлениеОшибки
-
ВызватьИсключение "Не удалось получить значение реквизита по причине: " + ОписаниеОшибки();


привожу твой же текст - ПодробноеПредставление
// Не удалось получить значение реквизита по причине: {ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма(6)}: Недостаточно фактических параметров
// {ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма(20)}:		ВызватьИсключение "Не удалось получить значение реквизита по причине: " + Описание;
// {ВнешняяОбработка.ОписаниеОшибки.Форма.Форма.Форма(29)}:		ВызватьОшибкуНаСервере();


фактически не видно, на каком же выражении возникла реальная ошибка, видна только строка, где возникло исключение Форма(6)
я про строку
А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();


а ведь код может измениться к моменту анализа ошибки, и придется дополнительно исследовать, где же именно возникла ошибка.

а вот если использовать простое "ВызватьИсключение;", то получим правильный и полезный вариант, в котором сразу видно выражение, в котором возникла ошибка!

Недостаточно фактических параметров
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(82)}:     А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(53)}:     ВызватьОшибкуНаСервере();
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(7)}:  ВызватьОшибку(Команда);


в итоге совет - без очень веских причин никогда не используйте ВызватьИсключение Текст, а используйте простейшее ВызватьИсключение без параметра
Gendelf; SagittariusA; ShootNICK; fancy; tormozit; JohnyDeath; dabu-dabu; Drivingblind; TMV; Nicholas; +10 Ответить
8. Nicholas 902 10.11.21 05:13 Сейчас в теме
(5) Спасибо за отличный совет!
12. kuzyara 2091 10.11.21 10:40 Сейчас в теме
(5)
а вот если использовать простое "ВызватьИсключение;", то получим правильный и полезный вариант
Недостаточно фактических параметров
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(82)}:     А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(53)}:     ВызватьОшибкуНаСервере();	// 8.3.15+
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(7)}:  ВызватьОшибку(Команда);	// 8.3.15+
Стек только в 8.3.15 появился
При возникновении сообщений об ошибке, подробная информация об ошибке не содержала стек вызовов, который привел к строке с ошибкой (кроме случаев вложенных исключений). (с) V8Update :: 1С:Предприятие 8.3.15. Документация

То же и про ВызватьИсключение ;
&НаКлиенте
Процедура Команда1(Команда)
	Попытка
		ВызватьОшибку(Команда);
	Исключение
		ПодробноеПредставление = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
		// для 8.3.15+
		//Недостаточно фактических параметров
		//{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(30)}:     А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();
		//{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(20)}:     ВызватьОшибкуНаСервере();
		//{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(4)}:      ВызватьОшибку(Команда);
		
		// для 8.3.14 и ниже выведет:
		//{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(30)}: Недостаточно фактических параметров
		//А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();	
		
	КонецПопытки;
КонецПроцедуры

&НаКлиенте
Процедура ВызватьОшибку(Команда)
	
	Попытка
		ВызватьОшибкуНаСервере();
	Исключение
		ВызватьИсключение;
	КонецПопытки;
	
КонецПроцедуры

&НаСервере
Процедура ВызватьОшибкуНаСервере()
	Попытка
		А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();
	Исключение
		ВызватьИсключение;
	КонецПопытки;
КонецПроцедуры
Показать
crismar24; Nicholas; +2 Ответить
13. Nicholas 902 10.11.21 10:42 Сейчас в теме
(12) Не зря тему поднял. Много интересного узнаю)
14. artbear 1563 10.11.21 11:30 Сейчас в теме
(12) ты точно проверял?
я на 8.3.10 получаю стек вызовов в исключениях Ванесса-АДД, что я делаю не так?
15. kuzyara 2091 10.11.21 12:48 Сейчас в теме
(14) примерно так проверял
C:\Users\Nikolay.Kuznecov>"c:\Program Files (x86)\1cv8\8.3.10.2772\bin\1cv8.exe" ENTERPRISE /Execute C:\Users\Nikolay.Kuznecov\Desktop\ВнешняяОбработка1.epf

{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(37)}: Деление на 0
й=1/0;//А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();

C:\Users\Nikolay.Kuznecov>"c:\Program Files (x86)\1cv8\8.3.15.1830\bin\1cv8.exe" ENTERPRISE /Execute C:\Users\Nikolay.Kuznecov\Desktop\ВнешняяОбработка1.epf

Деление на 0
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(37)}: й=1/0;//А = ОбщегоНазначения.ЗначениеРеквизитаОбъекта();
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(27)}: ВызватьОшибкуНаСервере();
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(4)}: ВызватьОшибку();
{ВнешняяОбработка.ВнешняяОбработка1.Форма.Форма.Форма(45)}: Команда1(Неопределено);
Прикрепленные файлы:
ВнешняяОбработка1.epf
10. TMV 14 10.11.21 09:18 Сейчас в теме
Логично предположить, что это будет что-то вроде "Недостаточно фактических параметров".
Вот тут вывод мне не показался логичным.
11. Nicholas 902 10.11.21 09:20 Сейчас в теме
(10) Да, для примера нужно было использовать что-типа:
А = 1 / 0;
18. MaCCapAkIII 10.11.22 16:15 Сейчас в теме
И еще есть вопрос. Если мне нужно подменить отображаемый у пользователя текст ошибки на свой текст, а, собственно, информацию об ошибке записать в ЖР и дальше анализировать самостоятельно - это возможно без глобального описания в МодулеПриложения обработчика ошибок? Пользователя смущает длинная простыня кода на форме с сообщением об ошибке. Исключение вызывается программно через ВызватьИсключение в неудачной Попытке.
Попытка
 Какойтокод;
Исключение
 ЕщеКод;
 ВызватьИсключение КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;

Вот такая конструкция все равно выдает пользователю огромную простыню с с текстом кода, где только в самом начале одной строчкой говорится о недостатке прав. Хочу оставить только эту строчку (или написать свою), все остальное пользователю не показывать. Не могу найти как это сделать, кроме использования ОбработкиОтображенияОшибок в модуле приложения, но описывать этот блок работы с конфигурацией (ранее им никто не пользовался) будет дополнительно затратна по времени.
19. Nicholas 902 11.11.22 08:15 Сейчас в теме
(18) Боюсь, в данном случае, поможет только общий модуль.
20. MaCCapAkIII 11.11.22 09:15 Сейчас в теме
(19) Вы про контекст ошибки? То есть строить свою конструкцию по обработке каждой конкретной ошибки?
21. Nicholas 902 11.11.22 09:19 Сейчас в теме
(20) Тут уже от ваших возможностей и фантазии зависит. Можно, например, отправлять на почту сообщения об определенных ошибках, или даже создавать задачу в системе учета заявок по видам ошибок.
22. MaCCapAkIII 11.11.22 09:24 Сейчас в теме
(21) Это понятно. Меня пока интересует масштабы задачи по обработке конкретной ошибки. Странно, что в 1С нет рабочего механизма по управлению интерфейсными оповещениями пользователя об ошибках. А механизм настраиваемых шаблонов по критериям ошибок из Функций для разработчика - это тоже слишком общий алгоритм, обрабатывающий все ошибки по конкретному критерию.
23. nickstrelets 25.01.24 04:06 Сейчас в теме
(3) Может подскажите, почему в одной ситуации показывается конкретное место ошибки в подписке на событие "ПриЗаписи" справочника, а в другой показывается текст ошибки только до уровня Объект.Записать()?
Код, где происходи ошибка, находится в расширениях.
На скриншотах приведены примеры этих ситуаций
Скриншот 1 - база прод, выключен debug, не показывается конкретное место ошибки
Скриншот 2 - копия с включенной отладкой, показывается конкретное место ошибки
Прикрепленные файлы:
Оставьте свое сообщение