В процессе разработки на платформе 1С:Предприятие 8 часто возникает задача логирования ошибок непосредственно в момент записи объекта. Однако разработчики сталкиваются с фундаментальной особенностью механизма транзакций: если в процедуре ПередЗаписью установить параметр Отказ = Истина, платформа инициирует откат (Rollback) всей транзакции. В результате любые изменения, внесенные в базу данных внутри этой транзакции — включая записи в регистры сведений, предназначенные для логирования ошибок, — также аннулируются.
В этой статье мы подробно разберем, как обойти это ограничение, проанализируем различные подходы и выберем наиболее эффективные методы сохранения данных при отмене основной транзакции.
Прежде всего, проанализируем ситуацию с технической точки зрения. Когда мы работаем в подписке на событие или в модуле объекта ПередЗаписью, мы уже находимся внутри транзакции, открытой платформой. Любая попытка записи в базу данных (через НаборЗаписей или МенеджерЗаписи) становится частью этой же транзакции. Если выполнение кода прерывается установкой флага Отказ, СУБД возвращает состояние базы данных к моменту до начала транзакции. Именно поэтому стандартные методы записи внутри того же сеанса не работают.
Самый распространенный и эффективный способ, который мы рассмотрим, — это запуск фонового задания. Суть метода заключается в том, что фоновое задание запускается в отдельном сеансе. Поскольку это другой сеанс, у него своя собственная транзакция, которая никак не связана с транзакцией основного сеанса.
Разберем по шагам, как это реализовать:
ФоновыеЗадания.Выполнить.Рассмотрим пример кода для запуска такого задания:
Если Отказ Тогда
МассивПараметров = Новый Массив;
// Важно: передаем ссылку или идентификатор, а не сам объект!
МассивПараметров.Добавить(Источник.Ссылка);
МассивПараметров.Добавить(ТекстОшибки);
// Запускаем фоновое задание, которое запишет лог независимо
ФоновыеЗадания.Выполнить("КонтрольДанных.ЗаписатьОшибкиВРегистр", МассивПараметров);
КонецЕсли;
Важное замечание: При использовании этого метода необходимо помнить о сериализации. Все параметры, передаваемые в массив МассивПараметров, должны поддерживать сериализацию (например, ссылки, строки, числа, структуры). Если вы попытаетесь передать сам Объект (который еще не записан), система выдаст ошибку.
Проанализируем структуру процедуры в общем модуле КонтрольДанных:
Процедура ЗаписатьОшибкиВРегистр(Знач МассивПараметров) Экспорт
СсылкаНаОбъект = МассивПараметров[0];
ОписаниеОшибки = МассивПараметров[1];
МенеджерЗаписи = РегистрыСведений.ЛогОшибок.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = ТекущаяДата();
МенеджерЗаписи.Объект = СсылкаНаОбъект;
МенеджерЗаписи.ТекстОшибки = ОписаниеОшибки;
МенеджерЗаписи.Записать();
КонецПроцедуры
Для высоконагруженных систем или случаев, когда нужно гарантировать немедленную фиксацию данных, можно использовать механизм HTTP-сервисов. Вызов HTTP-сервиса «самого себя» создает новый независимый контекст выполнения.
Рассмотрим преимущества этого метода:
JSON, что позволяет передать гораздо больше информации о состоянии объекта в момент ошибки.Выясним, как это выглядит в коде:
Соединение = Новый HTTPСоединение("localhost", , Логин, Пароль);
Запрос = Новый HTTPЗапрос("/ВашаБаза/hs/Logger/v1/WriteError");
Запрос.УстановитьТелоИзСтроки(ДанныеОшибкиВФорматеJSON);
Ответ = Соединение.ОтправитьДляОбработки(Запрос);
Посмотрим на штатный механизм 1С — Журнал регистрации. Метод ЗаписатьСобытиеЖурналаРегистрации является одним из немногих, которые выполняются вне транзакции по определению. Если данные в регистре сведений вам нужны для последующего автоматизированного анализа, можно применить комбинированный подход:
Этот метод позволяет минимизировать нагрузку на сервер, так как запись в текстовый лог (которым по сути является Журнал регистрации) происходит быстрее, чем создание фонового задания или HTTP-вызов.
В некоторых случаях, когда база данных испытывает огромные нагрузки, запись логов внутри 1С (даже фоновым заданием) может быть нежелательна. Проанализируем вариант записи в текстовые файлы или специализированные системы сбора логов.
Пример простой записи в файл:
ТекстЛога = Новый ТекстовыйДокумент();
ТекстЛога.ДобавитьСтроку(Строка(ТекущаяДата()) + ": " + ОписаниеОшибки);
// Используем Попытку, чтобы ошибка записи лога не прервала работу пользователя
Попытка
ТекстЛога.Записать(ПутьКФайлуЛога, КодировкаТекста.UTF8);
Исключение
// Игнорируем ошибки записи лога
КонецПопытки;
Позже эти файлы можно обрабатывать отдельным скриптом или тем же регламентным заданием 1С.
Выберем подходящий вариант в зависимости от условий:
Подводя итог, отметим, что выбор метода ФоновыеЗадания.Выполнить является «золотым стандартом» для современного программиста 1С. Он позволяет сохранить логическую целостность системы, не перегружая её лишними внешними зависимостями, и при этом надежно сохранять информацию даже при возникновении критических ошибок бизнес-логики, приводящих к откату транзакции.