Почему в модуле объекта 1С отсутствует событие ПослеЗаписи() и как правильно реализовать логику после фиксации транзакции?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке в среде 1С:Предприятие программисты часто сталкиваются с необходимостью выполнить какие-либо действия строго после того, как объект был гарантированно записан в базу данных. Например, отправить уведомление по электронной почте, запустить внешнюю интеграцию или оповещить сторонний сервис через HTTP-запрос. Однако в модуле объекта мы видим только ПередЗаписью и ПриЗаписи. События ПослеЗаписи там просто не существует. Рассмотрим подробно, почему это так, и какие существуют способы решения этой задачи.

Архитектурные причины отсутствия события в модуле объекта

Проанализируем сначала внутреннюю логику работы платформы. Все события модуля объекта (ПередЗаписью, ПриЗаписи, ОбработкаПроведения), а также соответствующие им подписки на события, выполняются внутри одной неделимой транзакции. Это означает, что пока управление не вышло из этих процедур, данные еще не зафиксированы окончательно в базе данных (не выполнен Commit).

Выясним, к чему бы привело наличие события ПослеЗаписи в модуле объекта:

  1. Нарушение принципов целостности (ACID): Если транзакция уже завершена, данные записаны. Если в гипотетическом событии ПослеЗаписи произойдет критическая ошибка, платформе пришлось бы либо игнорировать её (что опасно), либо пытаться откатить уже зафиксированную транзакцию, что технически невозможно.
  2. Проблема распределенных систем: Модуль объекта отвечает за состояние данных самого объекта. Внешние действия (отправка SMS, Email) не являются частью состояния данных. Если письмо ушло, а транзакция вдруг сорвалась на финальном этапе, мы получим ситуацию, когда сообщение отправлено о событии, которое фактически не произошло.
  3. Жизненный цикл объекта: После фиксации транзакции контекст серверного объекта может быть уничтожен платформой для экономии памяти. Вызывать методы у объекта, который «уже всё сделал», архитектурно не совсем корректно.

Решение 1: Использование модуля формы

Если запись инициирована пользователем интерактивно, самым простым и логичным решением будет использование обработчика ПослеЗаписиНаСервере в модуле управляемой формы. Разберем, чем это удобно:

Однако этот метод не сработает, если объект записывается программно (например, обработкой или фоновым заданием), так как форма при этом не создается.

Решение 2: Использование вспомогательных таблиц (очередь задач)

Проанализируем ситуацию, когда нам нужно гарантированно выполнить действие после программной записи. Рассмотрим профессиональный подход, который используется в Библиотеке стандартных подсистем (БСП). Суть метода заключается в создании записи-задания в транзакции.

Алгоритм действий:

  1. В модуле объекта в процедуре ПриЗаписи мы записываем данные о необходимости действия в специальный Регистр Сведений (назовем его ОчередьУведомлений).
  2. Так как запись в регистр происходит в той же транзакции, что и запись основного объекта, она либо сохранится вместе с объектом, либо откатится вместе с ним.
  3. Настраиваем Регламентное задание, которое раз в минуту (или чаще) опрашивает этот регистр, выполняет действия (отправку писем и т.д.) и удаляет обработанные записи.

Посмотрим на пример кода в модуле объекта:


Процедура ПриЗаписи(Отказ)
    Если ОбменДанными.Загрузка Тогда
        Возврат;
    КонецЕсли;

    // Создаем запись в очереди для последующей обработки вне транзакции
    МенеджерЗаписи = РегистрыСведений.ОчередьУведомлений.СоздатьМенеджерЗаписи();
    МенеджерЗаписи.Объект = Ссылка;
    МенеджерЗаписи.ДатаСобытия = ТекущаяДатаСеанса();
    МенеджерЗаписи.Записать();
КонецПроцедуры

Решение 3: Использование планов обмена

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

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

Решение 4: Расширения и перехват событий

С появлением расширений конфигурации у нас появилась возможность использовать аннотацию &После. Посмотрим, поможет ли она в данном случае. Если мы напишем:


&После("ПередЗаписью")
Процедура Моя_ПослеПередЗаписью(Отказ)
    // Код все еще в транзакции!
КонецПроцедуры

Важно понимать: использование &После для процедур модуля объекта не выводит выполнение кода за пределы транзакции. Это лишь меняет очередность выполнения внутри транзакции. Поэтому данный метод не является полноценной заменой события ПослеЗаписи.

Опасности использования фоновых заданий напрямую

Иногда разработчики пытаются вызвать ФоновыеЗадания.Выполнить() прямо из процедуры ПриЗаписи. Разберем, почему это "кривой" путь:

Если вы всё же решили использовать фоновое задание, внутри него обязательно нужно реализовать механизм ожидания или повторных попыток чтения объекта. Но использование очереди через регистр (Решение 2) выглядит гораздо более надежным.

Выясним, как проверить целостность транзакции

В процессе обсуждения часто возникает вопрос: а что если в транзакции произошла ошибка, но мы хотим её "проглотить" и продолжить? Рассмотрим пример кода, который демонстрирует поведение системы:


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

// Последующие действия в этой же транзакции могут вызвать ошибку 
// "В данной транзакции уже происходили ошибки"

Именно поэтому любые внешние действия (рассылки, вызовы API) крайне не рекомендуется помещать в Попытка...Исключение внутри ПриЗаписи. Если почтовый сервер недоступен, это может заблокировать запись документа у пользователя, если вы не обработаете это максимально аккуратно. Использование отложенного выполнения через регистры полностью снимает эту проблему.

Резюме

Отсутствие ПослеЗаписи в модуле объекта — это не недоработка, а защита разработчика от создания нестабильного кода. Для реализации логики после записи мы рекомендуем:

  1. Для интерактивных действий пользователя — использовать ПослеЗаписиНаСервере в модуле формы.
  2. Для системной логики и интеграций — использовать механизм очереди задач на базе Регистров Сведений и Регламентных заданий.
  3. Для гарантированной доставки данных в другие системы — использовать Планы обмена.

Эти методы позволяют сохранить высокую производительность системы и гарантировать консистентность данных в базе.

← На главную