В процессе разработки и сопровождения сложных систем на базе 1С, таких как «Комплексная автоматизация» или «CRM», программисты часто сталкиваются с ситуацией «мистической» записи данных. Представьте: в регистр сведений внезапно записываются тысячи строк, хотя стандартный глобальный поиск по конфигурации не показывает явных мест вызова метода Записать(), а обычная точка останова в модуле набора записей не срабатывает. Разберем пошагово, как вычислить виновника записи, используя различные инструменты платформы.
Первым делом проанализируем поведение самого регистра. В модуле набора записей существуют предопределенные процедуры ПередЗаписью и ПриЗаписи. Важно помнить, что запись может инициироваться с установленным флагом ОбменДанными.Загрузка = Истина. В типовых конфигурациях в начале этих процедур часто стоит проверка, которая прерывает выполнение кода, если идет загрузка данных. Рассмотрим пример стандартного кода:
Процедура ПередЗаписью(Отказ, Замещение)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Дальнейшая логика
КонецПроцедуры
Если вы поставите точку останова после этой проверки, а запись будет производиться механизмом синхронизации или обмена, отладчик просто не остановится в нужном месте. Решение: всегда ставьте точку останова на самую первую строку процедуры (на само условие проверки флага загрузки). Это позволит вам поймать момент обращения к регистру в любом режиме.
Когда точка останова сработала, нам необходимо выяснить, какой именно алгоритм привел к записи. Для этого воспользуемся окном Стек вызовов (Call Stack). Проанализируем цепочку вызовов: если запись идет из общего модуля, название которого содержит слова «Почта», «Интеграция» или «CRM», мы сможем быстро перейти к исходному коду. Однако бывает, что запись происходит в фоновом задании. В этом случае убедитесь, что у вас включена отладка фоновых заданий в настройках предмета отладки, иначе выполнение кода пройдет мимо вашего внимания.
Если вы не хотите менять типовую конфигурацию или подозреваете, что запись идет через механизмы, которые сложно отследить напрямую, создадим Подписку на событие. В расширении выберите объект РегистрСведенийНаборЗаписей.ИмяВашегоРегистра и создайте обработчик для события ПередЗаписью. Этот метод гарантированно сработает при любой попытке изменения данных в регистре. Внутри обработчика можно прописать дополнительную проверку условий (например, количество записей в наборе), чтобы отладчик срабатывал только тогда, когда в регистр «валится» подозрительно большой объем данных.
Разберем ситуацию, когда отладчик по каким-то причинам не помогает. Попробуем использовать Замер производительности. Это мощный инструмент, который фиксирует выполнение каждой строки кода. Порядок действий следующий:
CRM_НепрочитанныеЭлектронныеПисьма).Замер покажет все места, где происходило обращение к менеджеру или набору записей этого регистра, даже если вызов был динамическим, через конструкцию вида РегистрыСведений[ИмяРегистра]. Вы увидите конкретные строки кода и количество времени, затраченное на их выполнение.
Выясним причину, по которой обычный поиск РегистрыСведений.CRM_НепрочитанныеЭлектронныеПисьма может не давать результатов. В современных конфигурациях часто используется универсальный код. Проанализируем ситуацию: разработчики могли написать функцию, которая принимает имя регистра в качестве параметра. В этом случае поиск должен быть более «гибким».
Попробуйте выполнить глобальный поиск по строке "CRM_НепрочитанныеЭлектронныеПисьма" (обязательно в кавычках). Это позволит найти места, где имя регистра используется как строковый литерал для обращения к метаданным. Также полезно выполнить поиск ссылок на объект метаданных через контекстное меню в дереве конфигурации.
Если записи появляются «сами собой» через некоторое время после завершения основного процесса, проанализируем список фоновых заданий. В консоли фоновых заданий (или через стандартную обработку в «Администрировании») сопоставим время появления записей в регистре со временем работы различных процессов. В CRM-системах часто после основного задания «Получение почты» запускаются цепочки других заданий:
Заглянем в Журнал регистрации. Настроим отбор по метаданным (наш регистр) и событию «Данные. Изменение». В колонке «Данные» мы увидим, какие именно записи были сделаны, а в колонке «Сеанс» — номер сеанса фонового задания. Зная номер сеанса, мы сможем точно определить, какое регламентное задание инициировало процесс.
В случае с регистром CRM_НепрочитанныеЭлектронныеПисьма в КА 2.4, проблема часто кроется в механизме синхронизации флагов прочтения. Проанализируем, как работает этот процесс: 1С запрашивает у почтового сервера список сообщений и их атрибуты. Если почтовый сервер (например, при использовании протокола IMAP) возвращает некорректные идентификаторы (UID) или если папка на сервере была перемещена, 1С может решить, что все старые письма — новые, и заново запишет их в регистр непрочитанных.
Посмотрим на код из типового модуля:
ЗаписьДействия.Действие = ?(НЕ Прочитано,
Перечисления.CRM_ДействияПоIMAP.УстановитьФлагПрочтения,
Перечисления.CRM_ДействияПоIMAP.СнятьФлагПрочтения);
Этот фрагмент указывает на наличие очереди отложенных операций. То есть запись в ваш регистр может быть следствием обработки этой очереди другим процессом. Проверьте состояние регистра CRM_ОтложенныеОперацииПоIMAP — возможно, причина массовых записей кроется в накоплении ошибок синхронизации именно там.
Если даже замер производительности не вносит ясности, воспользуемся «тяжелой артиллерией» — Технологическим журналом. Мы можем настроить сбор события SDBL (запросы к базе данных) с фильтром по имени таблицы, соответствующей нашему регистру. В лог-файле Технологического журнала будет зафиксирован не только сам факт записи, но и полный стек вызовов на языке 1С. Это позволит увидеть всю цепочку даже в самых запутанных случаях, когда используются сложные схемы динамического исполнения кода или COM-соединения.