Как обеспечить мгновенное отображение обновленных цен в 1С:Управление торговлей 11.4 после фоновой загрузки данных без перезапуска программы?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Причина возникновения проблемы: механизмы кэширования и взаимодействия клиента и сервера

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

  1. Кэширование на сервере 1С:Предприятия: Сервер приложений 1С хранит часто используемые данные и метаданные в своей оперативной памяти. Это ускоряет выполнение запросов и операций с базой данных, так как не всегда требуется обращение к СУБД.
  2. Кэширование на клиенте: Клиентское приложение (будь то тонкий клиент или веб-клиент) также кэширует определенные данные и метаданные. Когда пользователь открывает форму, данные для нее загружаются с сервера и могут храниться в клиентском кэше. Последующие обращения к тем же данным могут использовать кэшированную версию, если система считает ее актуальной.
  3. Асинхронные операции: Регламентные задания выполняются на сервере в отдельном процессе. Они изменяют данные непосредственно в базе данных. Однако эти изменения не автоматически транслируются всем активным клиентским сессиям. Клиентское приложение не "знает", что произошло фоновое обновление, и продолжает работать с той версией данных, которая была загружена и кэширована в момент открытия формы или выполнения запроса.

Таким образом, когда фоновое задание обновляет цены в регистре сведений, серверные данные обновляются, но клиентские сессии продолжают оперировать "устаревшими" копиями. Это приводит к ситуации, когда пользователи видят неактуальные цены, пока не выполнят действия, которые принудительно заставят клиентское приложение запросить свежие данные с сервера (например, перезапуск программы, переоткрытие формы, или специальное обновление).

Основное решение: метод ОповеститьОбИзменении()

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

Что делает ОповеститьОбИзменении()?

Метод ОповеститьОбИзменении() отправляет сигнал всем открытым формам клиентского приложения, сообщая им о том, что данные определенного типа (или конкретного объекта) могли быть изменены. Если форма настроена соответствующим образом (например, использует динамическое обновление данных, подписывается на оповещения или ее элементы управления связаны с изменяемыми данными), она может отреагировать на это оповещение и запросить свежие данные с сервера для перерисовки.

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

Как использовать ОповеститьОбИзменении() для обновления цен?

В нашем сценарии с обновлением цен, которые хранятся в регистре сведений, наиболее эффективным будет оповещение об изменении метаданного самого регистра сведений. Рассмотрим шаги и примеры кода.

  1. Определяем метаданные, которые были изменены:

    В случае с ценами, мы обновляем записи в регистре сведений, который обычно называется "ЦеныНоменклатуры" или аналогично. Нам нужно получить тип ссылки на этот регистр.

    Например, если вы обновляете данные в регистре сведений "ЦеныНоменклатуры", вы должны оповестить об изменении именно этого регистра:

    
    // В вашей серверной процедуре регламентного задания, после записи новых цен
    // ... (код обновления цен в регистре сведений)
    // После успешной записи всех изменений в регистр:
    ОповеститьОбИзменении(Тип("РегистрСведенийСсылка.ЦеныНоменклатуры"));
    

    Обратите внимание, что мы передаем не конкретную запись регистра, а Тип("РегистрСведенийСсылка.ЦеныНоменклатуры"). Это сигнализирует системе, что любые формы, использующие данные из этого регистра (или подписанные на него), должны рассмотреть возможность обновления.

  2. Размещение вызова в коде регламентного задания:

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

    
    // Пример процедуры, вызываемой регламентным заданием
    Процедура ВыполнитьОбновлениеЦенРегламентноеЗадание() Экспорт
    
        // Открываем транзакцию, если необходимо
        НачатьТранзакцию();
        Попытка
            // ... Ваш код загрузки и обновления цен из Excel-файла ...
            // Пример:
            // Для Каждой СтрокаДанных Из ТаблицаЦен Из ТаблицаЦен Тогда
            //     ЗаписьРегистраЦен = РегистрыСведений.ЦеныНоменклатуры.СоздатьМенеджерЗаписи();
            //     ЗаписьРегистраЦен.Период = ТекущаяДата();
            //     ЗаписьРегистраЦен.Номенклатура = СтрокаДанных.Номенклатура;
            //     ЗаписьРегистраЦен.ВидЦены = СтрокаДанных.ВидЦены;
            //     ЗаписьРегистраЦен.Цена = СтрокаДанных.НоваяЦена;
            //     ЗаписьРегистраЦен.Записать();
            // КонецДля;
            // ...
    
            // Фиксируем изменения в базе данных
            ЗафиксироватьТранзакцию();
    
            // Оповещаем активные сессии об изменении цен
            ОповеститьОбИзменении(Тип("РегистрСведенийСсылка.ЦеныНоменклатуры"));
    
        Исключение
            // Откатываем транзакцию в случае ошибки
            ОтменитьТранзакцию();
            ЗаписьЖурналаРегистрации("ОбновлениеЦен", УровеньЖурналаРегистрации.Ошибка, , , ОписаниеОшибки());
        КонецПопытки;
    
    КонецПроцедуры
    
  3. Оповещение об изменении справочников:

    В некоторых случаях, если цены тесно связаны с элементами справочника (например, через реквизиты или если формы справочника напрямую отображают агрегированные данные по ценам), может быть полезно также оповестить об изменении типа справочника Номенклатура или конкретного элемента, если изменялись данные только для него:

    
    // Если вы обновляете данные, непосредственно относящиеся к конкретному элементу справочника
    // Например, если в справочнике "Номенклатура" есть какой-то реквизит, связанный с ценой
    // (что менее характерно для цен, которые обычно в регистрах)
    ОповеститьОбИзменении(Тип("СправочникСсылка.Номенклатура"), НоменклатураОбъект.Ссылка);
    
    // Или, чтобы оповестить о потенциальном изменении любого элемента справочника
    ОповеститьОбИзменении(Тип("СправочникСсылка.Номенклатура"));
    

    Однако, для регистров сведений, как правило, достаточно оповещения об изменении самого типа регистра.

Важные аспекты и дополнительные рекомендации

Хотя метод ОповеститьОбИзменении() является мощным инструментом, важно понимать его ограничения и контекст использования, чтобы избежать недопонимания и возможных проблем.

  1. Действие только для активных сессий:

    Метод ОповеститьОбИзменении() отправляет оповещение только тем клиентским сессиям, которые активны в момент вызова метода. Если пользователь запускает программу или открывает форму уже после того, как оповещение было отправлено, он, естественно, сразу увидит актуальные данные. Но для пользователей, которые уже были в системе и имели открытые формы с устаревшими данными, оповещение служит сигналом к возможному обновлению.

    Важно отметить, что оповещение не гарантирует мгновенного "мэджик-обновления" всех открытых форм. Форма должна быть разработана таким образом, чтобы реагировать на эти оповещения. В управляемых формах многие стандартные элементы (например, динамические списки, поля, связанные с данными форм) умеют автоматически реагировать на такие оповещения.

  2. Переоткрытие форм или ручное обновление:

    Даже с использованием ОповеститьОбИзменении(), для некоторых форм, особенно тех, которые используют сложные запросы СКД или кэшируют данные специфическим образом, может потребоваться ручное переоткрытие формы пользователем или нажатие кнопки "Обновить" для гарантированного отображения свежих данных. Мы не можем исключать человеческий фактор.

  3. Различие с ОбновитьИнформационнуюБазу():

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

  4. Проверка механизмов кэширования конфигурации:

    Конфигурации, такие как 1С:Управление торговлей, могут иметь собственные, более сложные механизмы кэширования. Например, это могут быть общие модули, которые кэшируют результаты дорогостоящих запросов или значения, используемые многократно. Если в вашей конфигурации используются такие механизмы, их тоже необходимо учитывать.

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

  5. Особенности работы форм на управляемых интерфейсах:

    В управляемых формах 1С платформа автоматически подписывается на оповещения для многих элементов данных формы. Например, если у вас на форме есть поле, связанное с реквизитом, который ссылается на регистр сведений, и этот регистр был изменен, платформа попытается обновить данные в этом поле после оповещения.

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

Шаги для внедрения решения

Давайте подытожим наши действия, чтобы последовательно внедрить решение для своевременного отображения цен после фонового обновления:

  1. Идентифицируем регламентное задание и обработку:

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

  2. Находим место для вставки кода оповещения:

    Код с вызовом ОповеститьОбИзменении() следует поместить в конец серверной процедуры, которая непосредственно занимается записью данных цен в регистр сведений. Это должно произойти после того, как все изменения были успешно записаны и транзакция (если используется) зафиксирована.

  3. Вставляем код:

    Предположим, что наш регистр сведений называется ЦеныНоменклатуры. Мы добавляем следующую строку:

    
    // ... Ваш код обновления цен в регистре сведений ...
    
    // После успешного сохранения всех изменений
    ОповеститьОбИзменении(Тип("РегистрСведенийСсылка.ЦеныНоменклатуры"));
    

    Если в вашем решении цены затрагивают не только регистры, но и другие метаданные (например, реквизиты справочников), то имеет смысл оповещать и о них, передавая соответствующие типы ссылок. Однако для большинства случаев с ценами достаточно оповестить регистр сведений.

  4. Тестируем решение:

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

  5. Мониторинг производительности:

    Метод ОповеститьОбИзменении() сам по себе не является ресурсоемким. Однако, если у вас очень большое количество активных пользователей и очень частые обновления данных, это может приводить к повышенной активности на стороне клиента по обновлению форм. В большинстве случаев это не является проблемой, но стоит это учитывать при мониторинге производительности системы.

Таким образом, проблема устаревших данных после фонового обновления цен в 1С:Управление торговлей 11.4 успешно решается благодаря использованию метода ОповеститьОбИзменении(). Этот подход позволяет нам эффективно информировать активные клиентские сессии об изменениях, минимизируя необходимость ручного вмешательства пользователей и повышая общую актуальность информации в системе.

← На главную