Вот тебе, бабка и безопасные вычисления! БСП

У клиента на релизе БП 3.0.165.21 перестала работать моя универсальная обработка загрузки данных.

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

База была серверная, отладка не доступна. Я грешил на ошибку базы данных, предлагал сделать тестирование и исправление. Искал решение на форумах.

Но оказалось, что в другой базе загрузка работал. Пока не обновили на этот релиз.

В журнале регистрации выглядело как классический откат транзакции:

Но я не использовал транзакции в своем коде.

Пришлось сделать файловую копию базы и разбираться.

И тут же нашлась ошибка.

Обратите внимание, как сейчас выглядит код функции ОбщегоНазначения.ВычислитьВБезопасномРежиме:

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

Как видите, транзакция отменяется. Ранее такого не было, так что 1С пошла на изменение поведения функции. Зачем — непонятно. Вот код функции из предыдущих релизов:

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

Поэтому я временно отказался от этой функции, использую свою.

Функцию применял, чтобы пройти аудит во фреше. Теперь, похоже, такого рода обработки аудит во фреше не пройдут.

В итоге получилось, реализация записалась:

Меня удивляет, что 1С шатает из стороны в сторону и она не может определиться, как должен выглядеть код безопасного выполнения. Теперь добавила туда и транзакции, полностью исключив возможность изменения данных. При этом нарушив обратную совместимость функционала. Есть некая часть обработок для фреша, которые перестанут работать после этого обновления БСП.

Вот тебе, бабка, и Юрьев День!

Можно попробовать вызывать код в транзакции, тогда ветка ТранзакцияАктивна не сработает.

Среда: БП 3.0.165.21 БСП 3.1.10.357 Объем: 2 час.

fixin

Программирую на 1С с 1999 года. В 1С просто Гений. В 2020 году ушел из офиса на вольные хлеба фриланса. Принимаю заказы.

Читайте также:

комментариев 6

  1. Серх*й:

    Если ТранзакцияАктивна() Тогда
    Результат = Вычислить(Выражение);
    Иначе
    НачатьТранзакцию();
    Попытка
    Результат = Вычислить(Выражение);
    ОтменитьТранзакцию();
    Исключение
    ОтменитьТранзакцию();
    ВызватьИсключение;
    КонецПопытки;
    КонецЕсли;

    Как-то не очень логично, зачем что-то пытаться вычислять здесь, если всё равно будет откат транзакции.. Ps Походу индусов понабрали)

  2. rzd:

    Получается обработка неуниверсальная

  3. bob32:

    Транзакции и обработка исключений — это правильный подход. Базироваться на ошибка и недетерминированном поведении плохо, рано или поздно выстрелит (в других языках и framework-ах так же). Так что обновляй обработки свои.

    • Обновить не получится, для фреша будут обрезанные версии без универсальности. Теперь универсальность там не возможна.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *