Вот тебе, бабка и безопасные вычисления! БСП
У клиента на релизе БП 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 час.
Если ТранзакцияАктивна() Тогда
Результат = Вычислить(Выражение);
Иначе
НачатьТранзакцию();
Попытка
Результат = Вычислить(Выражение);
ОтменитьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецЕсли;
Как-то не очень логично, зачем что-то пытаться вычислять здесь, если всё равно будет откат транзакции.. Ps Походу индусов понабрали)
или студентов.
Получается обработка неуниверсальная
какая именно?
Транзакции и обработка исключений — это правильный подход. Базироваться на ошибка и недетерминированном поведении плохо, рано или поздно выстрелит (в других языках и framework-ах так же). Так что обновляй обработки свои.
Обновить не получится, для фреша будут обрезанные версии без универсальности. Теперь универсальность там не возможна.