В практике разработки на платформе «1С:Предприятие» часто возникает задача: необходимо выполнить определенные действия (например, расчет итогов, заполнение связанных регистров или отправку уведомлений) сразу после того, как документ был записан. Однако основная сложность заключается в том, что стандартный обработчик ПриЗаписи в модуле объекта выполняется внутри транзакции. Если мы попытаемся выполнить запрос к базе данных внутри этой транзакции, чтобы получить актуальные данные документа по ссылке, мы можем столкнуться с ограничениями уровней изоляции или тем, что данные еще не окончательно зафиксированы для других сеансов.
В этой статье мы подробно разберем, как обойти эти ограничения и гарантировать выполнение кода только после успешного завершения записи (Commit). Для решения подобных задач в интерфейсе также можно использовать платформу для создания программных роботов, которые автоматизируют действия пользователя.
Разберем ситуацию: когда выполняется код в процедуре ПриЗаписи, транзакция еще активна. Если в этот момент запустить процедуру, которая делает сложную выборку по базе данных (например, остатки с учетом текущего документа), запрос может вернуть неактуальные данные, так как физически изменения в таблицы базы данных еще не подтверждены. Если же транзакция по какой-то причине прервется (произойдет Отказ = Истина), а ваша процедура уже выполнит действия (например, отправит HTTP-запрос во внешнюю систему), возникнет логическая ошибка. Поэтому нам нужно решение, гарантирующее «выход» за пределы транзакции. Для отслеживания порядка вызова обработчиков можно использовать инструмент для изучения событий 1С.
Проанализируем самый современный и рекомендуемый способ, появившийся в последних версиях платформы. Фирма «1С» добавила штатный механизм, который позволяет зарегистрировать обработчик, выполняемый автоматически после успешной фиксации транзакции.
Рассмотрим пример реализации в модуле документа:
Процедура ПриЗаписи(Отказ)
// Регистрируем процедуру, которая выполнится ПОСЛЕ фиксации транзакции
ОписаниеОповещения = Новый ОписаниеОповещения("ВыполнитьОбработкуПослеЗаписи", ЭтотОбъект);
ЗапуститьПослеЗавершенияТранзакции(ОписаниеОповещения);
КонецПроцедуры
Процедура ВыполнитьОбработкуПослеЗаписи(Параметры) Экспорт
// Здесь документ уже гарантированно записан, и транзакция завершена.
// Можно выполнять запросы и обновлять связанные данные.
ВыполнитьСложныеРасчетыПоДокументу(ЭтотОбъект.Ссылка);
КонецПроцедуры
Важно помнить: если транзакция будет отменена, процедура ВыполнитьОбработкуПослеЗаписи просто не запустится. Это наиболее безопасный и производительный метод.
Если ваша платформа ниже версии 8.3.25, рассмотрим классический «хак», который часто применяется в высоконагруженных системах. Суть метода заключается в запуске фонового задания прямо из транзакции записи.
Алгоритм работы:
ПриЗаписи мы запускаем фоновое задание и передаем ему ссылку на наш документ.Посмотрим на пример кода в модуле документа:
Процедура ПриЗаписи(Отказ)
Если Отказ Тогда Возврат; КонецЕсли;
ПараметрыЗадания = Новый Структура;
ПараметрыЗадания.Вставить("СсылкаНаДокумент", ЭтотОбъект.Ссылка);
ФоновыеЗадания.Выполнить("ОбщийМодульСервер.ОбработатьДокументПослеЗаписи", ПараметрыЗадания);
КонецПроцедуры
И код в общем модуле (с установленным флагом «Сервер»):
Процедура ОбработатьДокументПослеЗаписи(Параметры) Экспорт
СсылкаНаДокумент = Параметры.СсылкаНаДокумент;
// Пытаемся заблокировать объект.
// Если транзакция записи еще идет, выполнение здесь приостановится платформой.
Блокировка = Новый БлокировкаДанных;
ЭлементБлокировки = Блокировка.Добавить("Документ.РеализацияТоваровУслуг");
ЭлементБлокировки.УстановитьЗначение("Ссылка", СсылкаНаДокумент);
ЭлементБлокировки.Режим = РежимБлокировкиДанных.Исключительный;
Попытка
Блокировка.Заблокировать();
// Если мы здесь — транзакция основного сеанса завершена.
// Проверяем, существует ли документ (на случай, если транзакция была отменена)
Если СсылкаНаДокумент.Пустая() Или Не ОбщегоНазначения.ОбъектСуществует(СсылкаНаДокумент) Тогда
Возврат;
КонецЕсли;
// Выполняем полезную работу
АктуализироватьДополнительныеДанные(СсылкаНаДокумент);
Исключение
// Обработка ошибки блокировки или выполнения
ЗаписьЖурналаРегистрации("Ошибка после записи документа", УровеньЖурналаРегистрации.Ошибка,,, ОписаниеОшибки());
КонецПопытки;
КонецПроцедуры
Если вы работаете в современной конфигурации (ERP, КА, УТ 11, БП 3.0), выясним, как использовать штатные механизмы БСП. Использование подсистемы «Очередь заданий» — это более надежный способ, чем ручной запуск фоновых заданий, так как БСП берет на себя управление очередностью и повторные попытки при сбоях.
Выясним причину, почему это удобно: вы просто записываете намерение выполнить действие в специальный регистр сведений (Очередь заданий) в той же транзакции. Если запись документа пройдет успешно — запись в очереди тоже сохранится. Если будет откат — запись в очереди исчезнет. Регламентное задание подхватит вашу задачу через несколько секунд после фиксации. Для полноценного использования этого механизма доступен раздел с решениями для перехода на 1С:ERP и другие современные системы.
Пример использования метода БСП ОчередьЗаданий.ДобавитьЗадание:
// В модуле документа
Процедура ПриЗаписи(Отказ)
Если ОбменДанными.Загрузка Тогда Возврат; КонецЕсли;
ПараметрыМетода = Новый Массив;
ПараметрыМетода.Добавить(ЭтотОбъект.Ссылка);
Задание = Новый Структура;
Задание.Вставить("ИмяМетода", "ОбщийМодульСервер.МояПроцедураОбработки");
Задание.Вставить("Параметры", ПараметрыМетода);
// БСП сама определит, когда выполнить это задание после фиксации транзакции
ОчередьЗаданий.ДобавитьЗадание(Задание);
КонецПроцедуры
Проанализируем ситуацию в высоконагруженных системах, где важно максимально быстро освободить рабочий процесс. Метод заключается в отправке асинхронного HTTP-запроса к опубликованному HTTP-сервису этой же базы данных.
Почему это работает? HTTP-запрос инициирует новое соединение с базой данных. Поскольку сетевой пакет дойдет до веб-сервера и вернется в 1С через микросекунды после отправки, а отправка происходит в самом конце процедуры ПриЗаписи, вероятность того, что транзакция уже завершится, крайне высока. Но для надежности в HTTP-сервисе все равно стоит использовать проверку существования данных или краткую паузу/повтор (Retry).
Рассмотрим критерии, по которым стоит выбирать решение:
ЗапуститьПослеЗавершенияТранзакции. Это нативно, быстро и не создает лишних сеансов.ПослеЗаписи. Но помните, что при записи программно (обработкой) этот код не выполнится.Выясним важный момент: никогда не используйте Предупреждение или Вопрос внутри транзакций для ожидания. Это блокирует ресурсы базы данных и может привести к зависанию всей системы. Используйте только асинхронные методы (фоновые задания или очереди).
Таким образом, мы рассмотрели все основные способы выполнения кода после фиксации документа. Правильный выбор инструмента позволит вам строить надежные и быстрые системы на базе «1С:Предприятие». В таких системах важно выявлять расхождения данных путём автоматической сверки проводок между информационными базами.