Разработка и Конфигурация · 14 мин
Подписки на события в 1С: когда они выполняются
Разбираем, в какой момент срабатывают подписки на события в 1С: порядок вызова обработчиков, транзакции, типовые события, ошибки и способы отладки.
Подписка на событие в 1С — это механизм, который позволяет выполнить произвольный код при наступлении определённого события объекта конфигурации: записи документа, проведения, заполнения, установки пометки удаления и других действий. Подписка не заменяет стандартные обработчики модуля объекта, а дополняет их: она срабатывает в строго определённый момент жизненного цикла объекта, и понимание этого момента критично для корректной работы доработок.
Главный вопрос, который возникает у разработчиков и администраторов, — когда именно выполняется подписка: до или после основного обработчика, внутри транзакции или вне её, на клиенте или на сервере. От ответа зависит, увидит ли код подписки уже записанные данные, сможет ли отменить действие и не сломает ли логику типовой конфигурации.
Материал ориентирован на тех, кто добавляет доработки без изменения типовых модулей, а также на тех, кто расследует «странное» поведение базы: лишние записи в регистрах, двойное срабатывание обработчиков, ошибки при проведении. Ниже разобран порядок вызова, особенности транзакций, типичные события и способы проверки.
Как устроен механизм подписок и где он определяется
Подписка на событие создаётся в конфигураторе в ветке «Общие» → «Подписки на события». В свойствах подписки указываются три ключевых параметра: источник (типы объектов, для которых она действует), событие (например, «ПриЗаписи», «ОбработкаПроведения», «ПередЗаписью») и обработчик — процедура в общем модуле, которая будет вызвана.
Обработчик подписки должен располагаться в общем модуле с установленным признаком «Сервер» (для серверных событий). Модуль также должен допускать вызов сервера, если подписка используется в управляемом приложении. Если модуль не удовлетворяет требованиям контекста, подписка просто не сработает или вызовет ошибку выполнения.
Важно понимать: подписка срабатывает для всех объектов, входящих в состав источника. Если в источнике указан «ДокументОбъект» без уточнения конкретных видов, обработчик будет вызываться для каждого документа конфигурации. Внутри обработчика при этом обязательно нужна проверка типа источника, иначе доработка начнёт влиять на непредусмотренные объекты.
Порядок вызова: подписка и модуль объекта
Строгий порядок таков: сначала выполняется обработчик события в модуле самого объекта (например, «ПередЗаписью» в модуле документа), затем вызываются обработчики подписок на это же событие. То есть подписка видит объект уже после того, как отработал типовой код модуля, включая установку параметров и возможные проверки.
Если на одно событие назначено несколько подписок, платформа не гарантирует порядок их вызова. Проектировать логику, где одна подписка зависит от результата другой, нельзя. Если последовательность критична, обе операции следует объединить в один обработчик одной подписки и управлять порядком внутри него.
Отдельный случай — события формы. Подписки на события форм не поддерживаются: механизм работает только для событий прикладных объектов (справочников, документов, регистров, планов обмена и т. д.). Если нужно вмешаться в поведение формы без изменения конфигурации, используются расширения, а не подписки.
Транзакции: в какой момент выполняется код подписки
События записи и проведения делятся на две группы по отношению к транзакции. События «ПередЗаписью», «ПриЗаписи», «ОбработкаПроведения», «ПриУстановкеПометкиУдаления» выполняются внутри транзакции записи. Это значит, что ошибка или явный вызов исключения в подписке откатит всю операцию — объект не будет записан или проведён.
События с приставкой «При…» после завершения действия, например «ОбработкаПроверкиЗаполнения», также работают в транзакции, а вот возможности отменить действие через параметр «Отказ» зависят от конкретного события. В «ПриЗаписи» отказ ещё возможен, но данные объекта к этому моменту уже переданы в базу — отказ инициирует откат транзакции целиком.
Практическое следствие: внутри подписки, выполняющейся в транзакции, нельзя начинать новую транзакцию записи того же объекта и нежелательно выполнять длительные операции — обращения к внешним сервисам, массовые расчёты. Пока транзакция открыта, удерживаются блокировки, что при высокой нагрузке приводит к конфликтам и тайм-аутам у других пользователей.
Типовые события и момент их срабатывания
Ниже перечислены наиболее используемые события и точный момент, когда выполняется подписка на каждое из них:
- ПриЗаполнении — при создании нового объекта интерактивно или программно с заполнением на основании; в транзакции записи не участвует.
- ПередЗаписью — до начала физической записи в базу, но уже внутри транзакции; можно изменить реквизиты и отменить запись через «Отказ».
- ПриЗаписи — после физической записи объекта, но до завершения транзакции; отказ ещё возможен, он откатит запись.
- ОбработкаПроверкиЗаполнения — при проверке обязательных реквизитов перед записью; типичное место для дополнительных контролей.
- ОбработкаПроведения — внутри транзакции проведения, до формирования движений стандартным обработчиком нет: сначала модуль объекта, потом подписка, и обе работают с набором записей до окончательной записи движений.
- ПриУстановкеПометкиУдаления — при интерактивной или программной установке/снятии пометки удаления.
- ПриКопировании — при создании объекта копированием.
Для регистров набор событий свой: «ПередЗаписью», «ПриЗаписи», «ОбработкаПроверкиЗаполнения» срабатывают для набора записей регистра. Подписки на регистры часто применяют для контроля корректности движений, но нужно учитывать, что обработчик вызывается при каждой записи набора, включая движения, формируемые при проведении документов.
Транзакция откатывается, объект остаётся в прежнем состоянии
Даже уже записанные данные будут отменены вместе с транзакцией
Нельзя строить зависимость одной подписки от результата другой
Нужна проверка типа источника в начале обработчика
Как проверить, что подписка выполняется, и найти причину молчания
Если подписка «не работает», проверку стоит вести по шагам. Сначала убедитесь, что обработчик находится в общем модуле с нужными признаками: «Сервер» включён, а если вызов идёт из клиентского контекста — включён и «Вызов сервера». Затем проверьте, что тип объекта, с которым вы работаете, действительно входит в состав источника подписки.
Далее убедитесь, что событие вообще наступает. Например, «ПриЗаполнении» не вызывается при программном создании объекта методом «СоздатьДокумент()» без параметров заполнения, а «ПередЗаписью» не сработает, если запись прервана ещё на этапе проверки заполнения в модуле объекта. Тонкий момент: метод «Записать()» объекта вызывает события, а прямая работа с наборами записей регистра — события регистра, но не события документа.
Для диагностики удобно временно добавить в обработчик запись в журнал регистрации через «ЗаписьЖурналаРегистрации» и затем посмотреть журнал в конфигураторе или консоли. Это безопаснее, чем «Сообщить», потому что работает и в фоновых заданиях, и на сервере без пользовательского интерфейса.
- 1Проверьте свойства общего модуля: включены «Сервер» и при необходимости «Вызов сервера»
- 2Убедитесь, что тип объекта входит в состав источника подписки
- 3Проверьте, что имя процедуры-обработчика совпадает с указанным в свойствах подписки
- 4Добавьте запись в журнал регистрации в первую строку обработчика
- 5Воспроизведите действие и найдите запись в журнале регистрации
- 6Если записи нет — событие не наступает: проверьте сценарий вызова (интерактивный/программный)
Типичные ошибки при работе с подписками
Самая частая ошибка — рекурсивный вызов: внутри подписки «ПриЗаписи» код снова вызывает «Записать()» того же объекта, что приводит к повторному срабатыванию подписки и зацикливанию или к ошибке вложенной транзакции. Если повторная запись необходима, используйте параметр «ДополнительныеСвойства» для передачи признака, что обработка уже выполнена.
Вторая распространённая проблема — отсутствие фильтрации по типу источника. Подписка с широким источником начинает обрабатывать объекты, для которых логика не предназначена, что приводит к ошибкам обращения к несуществующим реквизитам или к неожиданным изменениям данных в не связанных с доработкой документах.
Третья группа ошибок — обращение к данным, которых ещё нет. В событии «ПередЗаписью» у нового объекта ещё не установлен номер (для документов) или код может быть не присвоен; в «ОбработкаПроведения» движения ещё не записаны в базу. Запросы к базе в этот момент вернут старые данные, и логика, построенная на них, будет неверной.
Подписка или расширение: что выбрать для доработки
Подписки и расширения решают сходные задачи, но у каждого механизма свои границы. Подписка не требует изменения объектов конфигурации и работает даже тогда, когда модуль объекта недоступен для редактирования. Расширение позволяет переопределить обработчики конкретного объекта и формы, но требует аккуратного сопровождения при обновлениях.
| Критерий | Подписка на событие | Расширение конфигурации |
|---|---|---|
| Изменение типового модуля | Не требуется | Не требуется, обработчик переопределяется |
| Работа с формами | Не поддерживается | Поддерживается |
| Одна логика для многих объектов | Удобно, один обработчик на все типы | Нужно переопределять каждый объект |
| Порядок вызова | После типового обработчика модуля | Можно выполнить до, после или вместо типового |
| Риск при обновлении конфигурации | Низкий | Средний, нужна проверка переопределённых модулей |
Если задача — единая реакция на событие для группы объектов (например, аудит записи всех документов), подписка предпочтительнее. Если нужно вмешаться в логику конкретного объекта до типового обработчика или изменить поведение формы, выбирайте расширение.
Сравнение вариантов
Подходит для единой логики на группу объектов и для доработок без изменения модулей; ограничение — вызов только после типового обработчика и нет доступа к формам
Подходит для точечного изменения поведения конкретного объекта или формы; ограничение — необходимость контроля при обновлениях
Полный контроль над порядком выполнения; ограничение — снятие с поддержки и сложные обновления, применять в крайнем случае
Проверка результата после внедрения подписки
После добавления подписки проверьте её в трёх сценариях: интерактивная запись пользователем, программная запись из обработок или обменов и запись в фоновом задании. Контекст выполнения различается, и обработчик, работающий в одном сценарии, может не сработать или выдать ошибку в другом — например, из-за недоступности пользовательских функций на сервере.
Контрольные точки: объект записывается без ошибок, побочные действия подписки (создание связанных записей, регистрация к обмену) выполняются ровно один раз, при отказе в подписке данные не остаются в промежуточном состоянии. Особое внимание уделите нагрузочной проверке, если база многопользовательская: убедитесь, что обработчик не вызывает заметного роста времени записи.
Как проверить результат
Записывается без ошибок, логика подписки отрабатывает один раз
Ошибки, двойное срабатывание, зависание формы
Подписка выполняется и при обмене данными
Логика пропускается или падает в фоновых сеансах
Объект не записан, данных в базе нет
Частично записанные связанные данные после отказа
Рост времени незаметен для пользователей
Запись стала ощутимо медленнее, появились конфликты блокировок
Часто задаваемые вопросы
Выполняется ли подписка при обмене данными?
Да, события записи срабатывают и при загрузке данных через планы обмена, если загрузка выполняется обычной записью объекта. Однако при загрузке с параметром «Загрузка = Истина» часть логики типовых обработчиков может быть пропущена, поэтому поведение подписки в этом режиме нужно тестировать отдельно.
Можно ли отменить проведение документа из подписки?
Да, если подписка назначена на событие, где доступен параметр «Отказ», например «ОбработкаПроведения» или «ПередЗаписью». Установка «Отказ = Истина» приводит к откату транзакции, и документ не будет проведён. В событиях без параметра отказа отменить действие можно только вызовом исключения.
Почему подписка срабатывает дважды при одной записи?
Чаще всего причина в том, что внутри обработчика или в смежной логике объект записывается повторно, и каждая запись вызывает событие заново. Также проверьте, не создано ли две подписки с одинаковым источником и событием, вызывающие один и тот же обработчик.
В каком общем модуле должен находиться обработчик?
В общем модуле с включённым признаком «Сервер»; для вызова из клиентского контекста также нужен признак «Вызов сервера». Модуль не должен быть глобальным. Процедура обработчика должна быть экспортной и принимать параметры, соответствующие событию (источник, отказ и другие).
Видит ли подписка «ПриЗаписи» уже записанные данные?
Физическая запись в базу к моменту «ПриЗаписи» выполнена, но транзакция ещё не завершена. Запросы из того же сеанса увидят данные, однако при отказе или исключении всё будет откачено. Другие пользователи эти данные до завершения транзакции не увидят.
Что безопаснее для доработки типовой конфигурации: подписка или изменение модуля?
Подписка безопаснее: она не требует изменения типовых модулей и не усложняет обновление конфигурации. Изменение модуля объекта оправдано только тогда, когда нужно вмешаться в логику до типового обработчика, чего подписка сделать не позволяет.
Что важно запомнить
Подписка выполняется в момент наступления события объекта, после обработчика модуля объекта и внутри той же транзакции. Ошибка в подписке откатывает всю операцию. Порядок вызова нескольких подписок не гарантирован, а длительные операции внутри обработчика создают риск блокировок — выносите их в фоновые механизмы.