К статье
Практический материал

Разработка и Конфигурация · 14 мин

Когда вызывается подписка на событие в 1С

Разбираем, когда вызывается подписка на событие в 1С: порядок срабатывания обработчиков, транзакции, типовые ошибки и способы отладки подписок на события.

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

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

Механизм работает одинаково в клиент-серверном и файловом варианте, но с важными нюансами по контексту выполнения: обработчик подписки всегда исполняется на сервере, даже если запись инициирована на клиенте. Ниже разобран порядок вызова для каждого типа события, условия срабатывания и практика отладки.

Что такое подписка на событие и где она настраивается

Подписка на событие — объект метаданных в ветке «Общие» дерева конфигурации. В её свойствах указываются три ключевых параметра: источник (типы объектов, для которых срабатывает подписка), событие (момент вызова) и обработчик — экспортная процедура общего модуля, которая получит управление.

В качестве источника можно указать сразу несколько типов: например, все документы или конкретный набор справочников. Обработчик должен быть размещён в общем модуле с установленным флагом «Сервер»; для большинства событий также требуется флаг «Вызов сервера» не нужен, но модуль не должен быть клиентским. Сигнатура процедуры зависит от события: для «ПередЗаписью» это параметры Источник, Отказ, РежимЗаписи, РежимПроведения.

После добавления подписки изменения нужно сохранить и обновить конфигурацию базы данных — в отличие от внешних обработок, подписки являются частью конфигурации и не подхватываются «на лету».

Порядок вызова подписок по типам событий

Момент вызова определяется выбранным событием. Для документов и справочников наиболее используемы следующие варианты.

ПередЗаписью

Вызывается до начала транзакции записи в базу данных, после того как объект уже заполнен в памяти. В этой точке можно изменить реквизиты объекта, проверить данные и отменить запись, установив параметр Отказ = Истина. Данные в базе ещё старые: запросы к базе из обработчика вернут состояние до записи.

ПриЗаписи

Вызывается внутри транзакции записи, после того как данные объекта уже физически помещены в базу, но до фиксации транзакции. Здесь можно дозаписать связанные данные, сформировать движения вручную или отменить операцию — при Отказ = Истина транзакция откатывается целиком, включая саму запись объекта.

ОбработкаПроведения и ОбработкаУдаленияПроведения

Вызываются внутри транзакции проведения документа. Подписка на «ОбработкаПроведения» срабатывает вместе с (или вместо, если модуль документа пуст) одноимённым событием модуля объекта. Параметры: Источник, Отказ, РежимПроведения. Отмена проведения через Отказ откатывает всю транзакцию.

Прочие события

«ОбработкаЗаполнения» вызывается при создании объекта на основании или при стандартном заполнении. «ПриКопировании» — при создании копированием. «ОбработкаПроверкиЗаполнения» — при вызове проверки заполнения, до записи, если включена автоматическая проверка. «ПриУстановкеПометкиУдаления» — внутри транзакции установки или снятия пометки.

СобытиеМомент вызоваТранзакцияМожно отменить
ПередЗаписьюДо записи в БДВне транзакцииДа, запись не начнётся
ПриЗаписиДанные уже в БДВнутри транзакцииДа, откат всей транзакции
ОбработкаПроведенияПри проведенииВнутри транзакцииДа, откат движений
ОбработкаЗаполненияПри создании/вводе на основанииНетЧерез СтандартнаяОбработка
ПриУстановкеПометкиУдаленияПри пометке/снятии пометкиВнутри транзакцииДа

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

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

Относительно обработчика в модуле объекта картина определённее: сначала вызывается обработчик события модуля объекта, затем — обработчики подписок на то же событие. Это позволяет в подписках дорабатывать поведение типовых конфигураций, не изменяя модули самих объектов, что упрощает последующие обновления.

Параметр Отказ передаётся по цепочке: если модуль объекта или одна из подписок установила его в Истина, последующие обработчики могут быть не вызваны, а операция завершится с ошибкой. Поэтому в обработчике подписки стоит проверять входящее значение Отказ и не продолжать логику, если он уже истинен.

В каких ситуациях подписка вызывается всегда, а в каких — нет

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

Есть важное исключение: при загрузке данных с параметром ОбменДанными.Загрузка = Истина обработчики событий записи и проведения не вызываются — платформа намеренно пропускает бизнес-логику, чтобы ускорить загрузку и избежать побочных эффектов. Если подписка должна отрабатывать и при обмене, в начале обработчика нужна проверка Если Источник.ОбменДанными.Загрузка Тогда Возврат; КонецЕсли; — либо, наоборот, осознанное решение не добавлять её, если логика нужна и при загрузке.

Также подписка не вызовется, если запись выполняется методами, минующими объектную модель (например, прямые наборы записей с Записать(Истина) без чтения объекта для некоторых случаев), и если обработчик события вообще не наступает — например, «ОбработкаПроведения» не вызовется при простой записи документа без проведения.

Контекст выполнения и ограничения обработчика

Обработчик подписки всегда выполняется на сервере, в контексте того сеанса, который инициировал запись. Из него недоступны клиентские возможности: нельзя открыть форму, показать предупреждение модально, вызвать диалог. Для сообщений пользователю используется объект СообщениеПользователю или исключение через ВызватьИсключение — текст дойдёт до клиента при откате.

Внутри транзакционных событий («ПриЗаписи», «ОбработкаПроведения») запрещены действия, открывающие вложенные транзакции по тем же данным, и длительные операции: обращения к веб-сервисам, отправка писем, обмен с внешними системами. Такие вызовы удерживают блокировки и при недоступности внешнего ресурса откатывают запись. Правильный подход — в обработчике только зафиксировать факт необходимости отправки (например, записать в очередь через регистр сведений), а саму отправку выполнять регламентным заданием.

Ещё одно ограничение: общий модуль с обработчиком не должен иметь флагов «Клиент (обычное приложение)» или «Клиент (управляемое приложение)» как единственных — компиляция на сервере должна быть доступна. Привилегированный модуль допустим и часто оправдан, если подписка должна работать под пользователями без прав на изменяемые объекты.

Частая причина «подписка не работает» — обработчик размещён в общем модуле без флага «Сервер» или в модуле, не скомпилированном на сервере. Второй по частоте случай — в источнике подписки забыли отметить нужный тип объектов, и подписка просто не привязана к документу.
ПЗ
Практическое замечание

Как проверить и отладить вызов подписки

Самый надёжный способ убедиться, что подписка вызывается, — поставить точку останова в первой строке обработчика и выполнить запись объекта в отладочном сеансе. Если точка не сработала, проверяйте по списку: обновлена ли конфигурация базы данных, отмечен ли нужный тип в свойстве «Источник», стоит ли флаг «Сервер» у общего модуля, не установлено ли ОбменДанными.Загрузка при программной записи.

Для диагностики в рабочей базе, где отладка невозможна, временно добавьте в начало обработчика запись в журнал регистрации: ЗаписьЖурналаРегистрации("Подписка.Вызов", ...). По журналу видно и факт вызова, и переданные параметры, и пользователя, инициировавшего запись. После диагностики отладочный код удалите.

Полезно логировать и значение параметра РежимЗаписи для документов: поведение подписки часто должно различаться для режимов «Запись», «Проведение» и «ОтменаПроведения». Не проверяя режим, легко получить логику, которая срабатывает в неподходящие моменты.

Порядок действий при неработающей подписке
  1. 1
    Проверьте, что конфигурация базы данных обновлена после добавления подписки
  2. 2
    Убедитесь, что в свойстве «Источник» отмечен нужный тип объекта
  3. 3
    Проверьте, что общий модуль имеет флаг «Сервер» и обработчик объявлен с Экспорт
  4. 4
    Поставьте точку останова в первой строке обработчика и повторите запись
  5. 5
    Проверьте, не установлен ли ОбменДанными.Загрузка = Истина при программной записи
  6. 6
    Убедитесь, что событие вообще наступает: например, ОбработкаПроведения требует проведения, а не простой записи
Контрольные точки

Как проверить результат

Вызов обработчика
Норма

Точка останова в обработчике срабатывает при записи объекта

Тревожный признак

Точка не срабатывает ни при интерактивной, ни при программной записи

Отмена операции
Норма

При Отказ = Истина запись не сохраняется, пользователь видит сообщение

Тревожный признак

Объект записывается несмотря на установленный Отказ

Поведение при обмене
Норма

При загрузке через обмен подписка пропускается (если так задумано)

Тревожный признак

Подписка выполняет бизнес-логику при загрузке и порождает лишние данные

Типичные ошибки при работе с подписками

Первая и самая опасная — рекурсия: в обработчике «ПриЗаписи» объекта вызывается Записать() этого же объекта. Каждый вызов снова инициирует событие, стек переполняется, сеанс аварийно завершается. Если нужно изменить сам объект, делайте это в «ПередЗаписью» через реквизиты Источник, а не повторной записью.

Вторая группа ошибок — игнорирование параметра Отказ и режима записи. Обработчик, который не проверяет входящий Отказ, может выполнить тяжёлую логику впустую. Обработчик без анализа РежимЗаписи срабатывает и при отмене проведения, хотя задумывался только для проведения.

Третья типичная проблема — тяжёлые операции внутри транзакции: запросы по большим таблицам без индексов, обращения к внешним сервисам, запись десятков связанных объектов. Это удлиняет транзакцию, увеличивает число блокировок и взаимоблокировок в многопользовательской базе. Выносите всё, что не обязано быть атомарным с записью, в отложенные механизмы.

Типичные ошибки
01
Вызов Записать() того же объекта в его событии — рекурсия и падение сеанса
02
Отсутствие проверки ОбменДанными.Загрузка — логика срабатывает при обмене и дублирует данные
03
Обращение к веб-сервису внутри ПриЗаписи — длинные транзакции, блокировки и откаты записи
04
Игнорирование РежимаЗаписи — обработчик срабатывает при отмене проведения вместо проведения
05
Зависимость от порядка вызова нескольких подписок — логика ломается без видимой причины

Когда подписку лучше заменить другим механизмом

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

Для реакции на уже завершённые изменения (уведомления, синхронизация, аудит) лучше подходят регламентные задания по очереди или планы обмена — они не нагружают транзакцию записи. Для проверок, которые пользователь должен увидеть до записи, часто достаточно «ОбработкиПроверкиЗаполнения» вместо «ПередЗаписью».

Маршрут решения

Как выбрать действие

Логика нужна для многих типов документов сразуИспользуйте подписку на событие с несколькими источниками
Нельзя изменять типовую конфигурацию из-за обновленийВыносите доработку в подписку, а не в модуль объекта
Нужно отправить данные во внешнюю систему после записиВ подписке фиксируйте очередь, отправку делайте регламентным заданием
Логика касается одного объекта в собственной конфигурацииРазмещайте код в модуле объекта — так проще сопровождать
Итог

Что важно запомнить

Подписка вызывается платформой автоматически при наступлении выбранного события: «ПередЗаписью» — до транзакции, «ПриЗаписи» и «ОбработкаПроведения» — внутри неё. Обработчик работает на сервере, срабатывает при любом способе записи, но пропускается при ОбменДанными.Загрузка = Истина. Избегайте рекурсии, тяжёлых операций в транзакции и зависимости от порядка нескольких подписок.

Частые вопросы о подписках на события

Вызывается ли подписка при программной записи объекта из кода?

Да. Подписка срабатывает при любом вызове Записать() или Провести() независимо от того, откуда выполнен вызов — из формы, модуля, фонового задания или внешнего соединения. Единственное штатное исключение — запись с установленным ОбменДанными.Загрузка = Истина, при которой события намеренно пропускаются.

Можно ли из обработчика подписки изменить записываемый объект?

Да, но только в событии «ПередЗаписью»: изменяйте реквизиты через параметр Источник, и изменения попадут в базу вместе с основной записью. В «ПриЗаписи» данные объекта уже сохранены, и менять его реквизиты поздно — потребуется повторная запись, которая вызовет рекурсию.

Почему подписка не срабатывает при загрузке данных через обмен?

Потому что механизмы обмена записывают объекты с признаком ОбменДанными.Загрузка = Истина, при котором платформа не вызывает обработчики событий. Если логика всё же нужна при загрузке, уберите в обработчике проверку этого флага, но учтите риски: замедление обмена и возможные побочные эффекты на загружаемых данных.

В каком порядке выполняются модуль объекта и подписка на то же событие?

Сначала вызывается обработчик события в модуле объекта, затем — обработчики подписок. Это делает подписки удобным инструментом доработки типовых конфигураций: ваш код гарантированно выполняется после штатной логики и видит её результат, а сама конфигурация остаётся на поддержке.

Что произойдёт, если в обработчике подписки возникнет исключение?

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

Можно ли временно отключить подписку без изменения конфигурации?

Штатного флага отключения у подписки нет. Практические варианты: вынести в начало обработчика проверку константы-переключателя и завершать процедуру возвратом, либо снять подписку в расширении конфигурации. Первый способ безопаснее — он не требует обновления конфигурации и позволяет включать логику обратно без вмешательства разработчика.